@flux-ui/components 3.0.0-next.61 → 3.0.0-next.63
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/component/FluxActionStack.vue.d.ts +25 -19
- package/dist/component/FluxAspectRatio.vue.d.ts +4 -3
- package/dist/component/FluxBorderShine.vue.d.ts +1 -1
- package/dist/component/FluxCalendar.vue.d.ts +2 -6
- package/dist/component/FluxContainer.vue.d.ts +3 -2
- package/dist/component/FluxFilter.vue.d.ts +6 -7
- package/dist/component/FluxFilterBar.vue.d.ts +5 -4
- package/dist/component/FluxFilterBase.vue.d.ts +14 -11
- package/dist/component/FluxFilterDate.vue.d.ts +3 -6
- package/dist/component/FluxFilterDateRange.vue.d.ts +3 -6
- package/dist/component/FluxFilterOption.vue.d.ts +3 -6
- package/dist/component/FluxFilterOptionAsync.vue.d.ts +3 -6
- package/dist/component/FluxFilterOptions.vue.d.ts +3 -6
- package/dist/component/FluxFilterOptionsAsync.vue.d.ts +3 -6
- package/dist/component/FluxFilterRange.vue.d.ts +3 -7
- package/dist/component/FluxFilterWindow.vue.d.ts +3 -8
- package/dist/component/FluxFlex.vue.d.ts +30 -0
- package/dist/component/{FluxRow.vue.d.ts → FluxFlexItem.vue.d.ts} +5 -3
- package/dist/component/FluxGrid.vue.d.ts +3 -2
- package/dist/component/FluxGridColumn.vue.d.ts +3 -2
- package/dist/component/FluxKanbanColumn.vue.d.ts +3 -0
- package/dist/component/FluxScroller.vue.d.ts +32 -0
- package/dist/component/{FluxStack.vue.d.ts → FluxSplitView.vue.d.ts} +7 -6
- package/dist/component/{FluxColumn.vue.d.ts → FluxSplitViewPane.vue.d.ts} +4 -1
- package/dist/component/FluxSticky.vue.d.ts +34 -0
- package/dist/component/index.d.ts +6 -3
- package/dist/component/primitive/FilterBadge.vue.d.ts +2 -2
- package/dist/component/primitive/FilterItem.vue.d.ts +3 -2
- package/dist/component/primitive/SelectBase.vue.d.ts +4 -4
- package/dist/composable/private/index.d.ts +1 -0
- package/dist/composable/private/useSplitView.d.ts +23 -0
- package/dist/data/di.d.ts +19 -2
- package/dist/data/index.d.ts +0 -1
- package/dist/index.css +583 -331
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8755 -8109
- package/dist/index.js.map +1 -1
- package/dist/util/defineFilter.d.ts +3 -0
- package/dist/util/filter.d.ts +7 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/vite/defineFilterMacro.d.ts +3 -0
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite.js +217 -0
- package/dist/vite.js.map +1 -0
- package/package.json +11 -7
- package/src/component/FluxActionBar.vue +3 -4
- package/src/component/FluxActionStack.vue +3 -3
- package/src/component/FluxAspectRatio.vue +5 -3
- package/src/component/FluxBadgeStack.vue +4 -4
- package/src/component/FluxButtonStack.vue +6 -4
- package/src/component/FluxCalendar.vue +160 -157
- package/src/component/FluxContainer.vue +4 -2
- package/src/component/FluxFilter.vue +10 -11
- package/src/component/FluxFilterBar.vue +71 -15
- package/src/component/FluxFilterBase.vue +65 -51
- package/src/component/FluxFilterDate.vue +24 -8
- package/src/component/FluxFilterDateRange.vue +27 -9
- package/src/component/FluxFilterOption.vue +20 -10
- package/src/component/FluxFilterOptionAsync.vue +19 -11
- package/src/component/FluxFilterOptions.vue +26 -11
- package/src/component/FluxFilterOptionsAsync.vue +28 -12
- package/src/component/FluxFilterRange.vue +25 -11
- package/src/component/FluxFilterWindow.vue +25 -11
- package/src/component/FluxFlex.vue +53 -0
- package/src/component/FluxFlexItem.vue +40 -0
- package/src/component/FluxFormDateTimeInput.vue +3 -4
- package/src/component/FluxGrid.vue +4 -2
- package/src/component/FluxGridColumn.vue +4 -2
- package/src/component/FluxInfoStack.vue +3 -3
- package/src/component/FluxItemStack.vue +4 -4
- package/src/component/FluxKanbanColumn.vue +16 -3
- package/src/component/FluxNoticeStack.vue +3 -3
- package/src/component/FluxProgressBar.vue +4 -3
- package/src/component/FluxScroller.vue +63 -0
- package/src/component/FluxSplitView.vue +101 -0
- package/src/component/FluxSplitViewPane.vue +23 -0
- package/src/component/FluxSticky.vue +67 -0
- package/src/component/FluxTagStack.vue +4 -4
- package/src/component/FluxToolbar.vue +3 -4
- package/src/component/FluxToolbarGroup.vue +3 -4
- package/src/component/FluxTooltipProvider.vue +56 -25
- package/src/component/index.ts +6 -3
- package/src/component/primitive/FilterBadge.vue +2 -2
- package/src/component/primitive/FilterItem.vue +4 -2
- package/src/component/primitive/FilterMenuRenderer.ts +10 -5
- package/src/component/primitive/FilterOptionBase.vue +1 -1
- package/src/composable/private/index.ts +1 -0
- package/src/composable/private/useAsyncFilterOptions.ts +1 -1
- package/src/composable/private/useFilterOption.ts +1 -1
- package/src/composable/private/useSplitView.ts +249 -0
- package/src/composable/useFilterInjection.ts +3 -1
- package/src/css/component/Calendar.module.scss +11 -17
- package/src/css/component/Comment.module.scss +3 -11
- package/src/css/component/Filter.module.scss +6 -2
- package/src/css/component/Flex.module.scss +84 -0
- package/src/css/component/Flyout.module.scss +1 -0
- package/src/css/component/Kanban.module.scss +31 -28
- package/src/css/component/LayerPane.module.scss +5 -0
- package/src/css/component/Layout.module.scss +0 -41
- package/src/css/component/Legend.module.scss +3 -4
- package/src/css/component/Menu.module.scss +1 -0
- package/src/css/component/Pagination.module.scss +1 -1
- package/src/css/component/Pane.module.scss +1 -1
- package/src/css/component/Progress.module.scss +2 -2
- package/src/css/component/Scroller.module.scss +109 -0
- package/src/css/component/SplitView.module.scss +78 -0
- package/src/css/component/Sticky.module.scss +35 -0
- package/src/css/component/Tab.module.scss +1 -0
- package/src/css/component/Table.module.scss +1 -0
- package/src/css/component/Tooltip.module.scss +14 -0
- package/src/data/di.ts +22 -2
- package/src/data/index.ts +0 -1
- package/src/index.ts +11 -0
- package/src/util/defineFilter.ts +10 -0
- package/src/util/filter.ts +63 -0
- package/src/util/index.ts +2 -0
- package/src/vite/defineFilterMacro.ts +335 -0
- package/src/vite/index.ts +1 -0
- package/dist/data/filter.d.ts +0 -7
- package/src/component/FluxColumn.vue +0 -24
- package/src/component/FluxRow.vue +0 -24
- package/src/component/FluxStack.vue +0 -41
- package/src/data/filter.ts +0 -165
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { FluxFilterDefinition, FluxFilterOptionHeader, FluxFilterOptionItem, FluxFilterSpec, FluxFilterValue, FluxFilterValueSingle } from '@flux-ui/types';
|
|
2
|
+
import { DateTime } from 'luxon';
|
|
3
|
+
import type { FluxTranslate } from '~flux/components/data';
|
|
4
|
+
|
|
5
|
+
export function isFluxFilterOptionHeader(obj: object): obj is FluxFilterOptionHeader {
|
|
6
|
+
return 'title' in obj;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function isFluxFilterOptionItem(obj: object): obj is FluxFilterOptionItem {
|
|
10
|
+
return 'label' in obj && 'value' in obj;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isResettable(definition: FluxFilterDefinition | undefined, value: FluxFilterValue | undefined): boolean {
|
|
14
|
+
if (!definition || definition.defaultValue === undefined) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return !isFilterValueEqual(value, definition.defaultValue);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isFilterValueEqual(a: FluxFilterValue | undefined, b: FluxFilterValue | undefined): boolean {
|
|
22
|
+
if (a === b) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (DateTime.isDateTime(a) && DateTime.isDateTime(b)) {
|
|
27
|
+
return a.equals(b);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
31
|
+
return a.length === b.length && a.every((value, index) => isFilterValueEqual(value, b[index]));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function pickFilterCommon<T extends FluxFilterSpec>(props: T): FluxFilterSpec {
|
|
38
|
+
return {
|
|
39
|
+
name: props.name,
|
|
40
|
+
label: props.label,
|
|
41
|
+
icon: props.icon,
|
|
42
|
+
disabled: props.disabled,
|
|
43
|
+
defaultValue: props.defaultValue,
|
|
44
|
+
onChange: props.onChange,
|
|
45
|
+
onClear: props.onClear
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function generateMultiOptionsLabel(translate: FluxTranslate, options: FluxFilterOptionItem[], values: FluxFilterValueSingle[]): string | null {
|
|
50
|
+
const selected = options.filter(o => values.includes(o.value)).length;
|
|
51
|
+
|
|
52
|
+
if (selected <= 0) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (selected === 1) {
|
|
57
|
+
return options.find(o => values.includes(o.value))!.label;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return translate('flux.nSelected', {
|
|
61
|
+
n: selected
|
|
62
|
+
});
|
|
63
|
+
}
|
package/src/util/index.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { default as createDialogRenderer } from './createDialogRenderer';
|
|
2
2
|
export { default as createLabelForDateRange } from './createLabelForDateRange';
|
|
3
|
+
export { default as defineFilter, type FluxFilterDefinitionFactory } from './defineFilter';
|
|
4
|
+
export { generateMultiOptionsLabel, isFluxFilterOptionHeader, isFluxFilterOptionItem, isResettable, pickFilterCommon } from './filter';
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
const SCRIPT_SETUP_REGEX = /<script\b([^>]*)\bsetup\b([^>]*)>([\s\S]*?)<\/script>/gi;
|
|
4
|
+
|
|
5
|
+
function defineFilterMacro(): Plugin {
|
|
6
|
+
return {
|
|
7
|
+
name: '@flux-ui/components/define-filter-macro',
|
|
8
|
+
enforce: 'pre',
|
|
9
|
+
|
|
10
|
+
transform(code, id) {
|
|
11
|
+
if (!id.endsWith('.vue')) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!code.includes('defineFilter')) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let transformed = false;
|
|
20
|
+
|
|
21
|
+
const newCode = code.replace(SCRIPT_SETUP_REGEX, (match, before, after, content) => {
|
|
22
|
+
if (!content.includes('defineFilter')) {
|
|
23
|
+
return match;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (content.includes('__filterDefinitionFactory')) {
|
|
27
|
+
return match;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (containsTopLevelCall(content, 'defineOptions')) {
|
|
31
|
+
return match;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const wrapped = wrapDefineFilter(content);
|
|
35
|
+
|
|
36
|
+
if (wrapped === content) {
|
|
37
|
+
return match;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
transformed = true;
|
|
41
|
+
return `<script${before}setup${after}>${wrapped}</script>`;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!transformed) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
code: newCode,
|
|
50
|
+
map: null
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default defineFilterMacro;
|
|
57
|
+
|
|
58
|
+
function wrapDefineFilter(content: string): string {
|
|
59
|
+
const range = findTopLevelCall(content, 'defineFilter');
|
|
60
|
+
|
|
61
|
+
if (!range) {
|
|
62
|
+
return content;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const callExpression = content.slice(range.callStart, range.callEnd);
|
|
66
|
+
const replacement = `defineOptions({\n __filterDefinitionFactory: ${callExpression}\n})`;
|
|
67
|
+
|
|
68
|
+
return content.slice(0, range.callStart) + replacement + content.slice(range.callEnd);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function containsTopLevelCall(content: string, name: string): boolean {
|
|
72
|
+
return findTopLevelCall(content, name) !== null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
type CallRange = {
|
|
76
|
+
readonly callStart: number;
|
|
77
|
+
readonly callEnd: number;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
function findTopLevelCall(content: string, name: string): CallRange | null {
|
|
81
|
+
let parenDepth = 0;
|
|
82
|
+
let braceDepth = 0;
|
|
83
|
+
let bracketDepth = 0;
|
|
84
|
+
let inString: string | null = null;
|
|
85
|
+
let inComment: 'single' | 'multi' | null = null;
|
|
86
|
+
|
|
87
|
+
let i = 0;
|
|
88
|
+
|
|
89
|
+
while (i < content.length) {
|
|
90
|
+
const c = content[i];
|
|
91
|
+
const n = content[i + 1];
|
|
92
|
+
|
|
93
|
+
if (inComment === 'single') {
|
|
94
|
+
if (c === '\n') {
|
|
95
|
+
inComment = null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
i++;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (inComment === 'multi') {
|
|
103
|
+
if (c === '*' && n === '/') {
|
|
104
|
+
inComment = null;
|
|
105
|
+
i += 2;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
i++;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (inString) {
|
|
114
|
+
if (c === '\\') {
|
|
115
|
+
i += 2;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (c === inString) {
|
|
120
|
+
inString = null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
i++;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (c === '/' && n === '/') {
|
|
128
|
+
inComment = 'single';
|
|
129
|
+
i += 2;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (c === '/' && n === '*') {
|
|
134
|
+
inComment = 'multi';
|
|
135
|
+
i += 2;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (c === '"' || c === '\'' || c === '`') {
|
|
140
|
+
inString = c;
|
|
141
|
+
i++;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (c === '(') {
|
|
146
|
+
parenDepth++;
|
|
147
|
+
i++;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (c === ')') {
|
|
152
|
+
parenDepth--;
|
|
153
|
+
i++;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (c === '{') {
|
|
158
|
+
braceDepth++;
|
|
159
|
+
i++;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (c === '}') {
|
|
164
|
+
braceDepth--;
|
|
165
|
+
i++;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (c === '[') {
|
|
170
|
+
bracketDepth++;
|
|
171
|
+
i++;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (c === ']') {
|
|
176
|
+
bracketDepth--;
|
|
177
|
+
i++;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const isTopLevel = parenDepth === 0 && braceDepth === 0 && bracketDepth === 0;
|
|
182
|
+
|
|
183
|
+
if (!isTopLevel || !content.startsWith(name, i)) {
|
|
184
|
+
i++;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const prevChar = i > 0 ? content[i - 1] : '';
|
|
189
|
+
|
|
190
|
+
if (/[A-Za-z0-9_$]/.test(prevChar)) {
|
|
191
|
+
i++;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const afterName = i + name.length;
|
|
196
|
+
const nextChar = content[afterName];
|
|
197
|
+
|
|
198
|
+
if (nextChar && /[A-Za-z0-9_$]/.test(nextChar)) {
|
|
199
|
+
i++;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const callOpen = skipGenericAndWhitespace(content, afterName);
|
|
204
|
+
|
|
205
|
+
if (callOpen === -1 || content[callOpen] !== '(') {
|
|
206
|
+
i++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const callClose = matchClosingParen(content, callOpen);
|
|
211
|
+
|
|
212
|
+
if (callClose === -1) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
callStart: i,
|
|
218
|
+
callEnd: callClose + 1
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function skipGenericAndWhitespace(content: string, start: number): number {
|
|
226
|
+
let i = start;
|
|
227
|
+
|
|
228
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
229
|
+
i++;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (content[i] !== '<') {
|
|
233
|
+
return i;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
let depth = 1;
|
|
237
|
+
i++;
|
|
238
|
+
|
|
239
|
+
while (i < content.length && depth > 0) {
|
|
240
|
+
const c = content[i];
|
|
241
|
+
|
|
242
|
+
if (c === '<') {
|
|
243
|
+
depth++;
|
|
244
|
+
} else if (c === '>') {
|
|
245
|
+
depth--;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
i++;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
252
|
+
i++;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return i;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function matchClosingParen(content: string, openIndex: number): number {
|
|
259
|
+
let depth = 1;
|
|
260
|
+
let inString: string | null = null;
|
|
261
|
+
let inComment: 'single' | 'multi' | null = null;
|
|
262
|
+
|
|
263
|
+
let i = openIndex + 1;
|
|
264
|
+
|
|
265
|
+
while (i < content.length) {
|
|
266
|
+
const c = content[i];
|
|
267
|
+
const n = content[i + 1];
|
|
268
|
+
|
|
269
|
+
if (inComment === 'single') {
|
|
270
|
+
if (c === '\n') {
|
|
271
|
+
inComment = null;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
i++;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (inComment === 'multi') {
|
|
279
|
+
if (c === '*' && n === '/') {
|
|
280
|
+
inComment = null;
|
|
281
|
+
i += 2;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
i++;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (inString) {
|
|
290
|
+
if (c === '\\') {
|
|
291
|
+
i += 2;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (c === inString) {
|
|
296
|
+
inString = null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
i++;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (c === '/' && n === '/') {
|
|
304
|
+
inComment = 'single';
|
|
305
|
+
i += 2;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (c === '/' && n === '*') {
|
|
310
|
+
inComment = 'multi';
|
|
311
|
+
i += 2;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (c === '"' || c === '\'' || c === '`') {
|
|
316
|
+
inString = c;
|
|
317
|
+
i++;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (c === '(') {
|
|
322
|
+
depth++;
|
|
323
|
+
} else if (c === ')') {
|
|
324
|
+
depth--;
|
|
325
|
+
|
|
326
|
+
if (depth === 0) {
|
|
327
|
+
return i;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
i++;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return -1;
|
|
335
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as defineFilterMacro } from './defineFilterMacro';
|
package/dist/data/filter.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { FluxFilterEntryMap, FluxFilterOptionHeader, FluxFilterOptionItem, FluxFilterSpecMap } from '@flux-ui/types';
|
|
2
|
-
export type FluxFilterParsers = {
|
|
3
|
-
[K in keyof FluxFilterSpecMap]: (spec: FluxFilterSpecMap[K]) => FluxFilterEntryMap[K];
|
|
4
|
-
};
|
|
5
|
-
export declare const filterParsers: FluxFilterParsers;
|
|
6
|
-
export declare function isFluxFilterOptionHeader(obj: object): obj is FluxFilterOptionHeader;
|
|
7
|
-
export declare function isFluxFilterOptionItem(obj: object): obj is FluxFilterOptionItem;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
:class="$style.column"
|
|
4
|
-
:style="{'--gap': `${gap}px`}">
|
|
5
|
-
<slot/>
|
|
6
|
-
</div>
|
|
7
|
-
</template>
|
|
8
|
-
|
|
9
|
-
<script
|
|
10
|
-
lang="ts"
|
|
11
|
-
setup>
|
|
12
|
-
import type { VNode } from 'vue';
|
|
13
|
-
import $style from '~flux/components/css/component/Layout.module.scss';
|
|
14
|
-
|
|
15
|
-
const {
|
|
16
|
-
gap = 18
|
|
17
|
-
} = defineProps<{
|
|
18
|
-
readonly gap?: number;
|
|
19
|
-
}>();
|
|
20
|
-
|
|
21
|
-
defineSlots<{
|
|
22
|
-
default(): VNode[];
|
|
23
|
-
}>();
|
|
24
|
-
</script>
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
:class="$style.row"
|
|
4
|
-
:style="{'--gap': `${gap}px`}">
|
|
5
|
-
<slot/>
|
|
6
|
-
</div>
|
|
7
|
-
</template>
|
|
8
|
-
|
|
9
|
-
<script
|
|
10
|
-
lang="ts"
|
|
11
|
-
setup>
|
|
12
|
-
import type { VNode } from 'vue';
|
|
13
|
-
import $style from '~flux/components/css/component/Layout.module.scss';
|
|
14
|
-
|
|
15
|
-
const {
|
|
16
|
-
gap = 18
|
|
17
|
-
} = defineProps<{
|
|
18
|
-
readonly gap?: number;
|
|
19
|
-
}>();
|
|
20
|
-
|
|
21
|
-
defineSlots<{
|
|
22
|
-
default(): VNode[];
|
|
23
|
-
}>();
|
|
24
|
-
</script>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<Component
|
|
3
|
-
:is="tag ?? 'div'"
|
|
4
|
-
:class="clsx(
|
|
5
|
-
direction === 'horizontal' && $style.stackHorizontal,
|
|
6
|
-
direction === 'vertical' && $style.stackVertical,
|
|
7
|
-
isCentered && $style.isCentered,
|
|
8
|
-
isFill && $style.isFill,
|
|
9
|
-
isWrapping && $style.isWrapping
|
|
10
|
-
)"
|
|
11
|
-
:style="{
|
|
12
|
-
'--gap': gap != null ? `${gap}px` : undefined
|
|
13
|
-
}">
|
|
14
|
-
<slot/>
|
|
15
|
-
</Component>
|
|
16
|
-
</template>
|
|
17
|
-
|
|
18
|
-
<script
|
|
19
|
-
lang="ts"
|
|
20
|
-
setup>
|
|
21
|
-
import type { FluxDirection } from '@flux-ui/types';
|
|
22
|
-
import { clsx } from 'clsx';
|
|
23
|
-
import type { VNode } from 'vue';
|
|
24
|
-
import $style from '~flux/components/css/component/Layout.module.scss';
|
|
25
|
-
|
|
26
|
-
const {
|
|
27
|
-
direction = 'vertical',
|
|
28
|
-
gap = 18
|
|
29
|
-
} = defineProps<{
|
|
30
|
-
readonly direction?: FluxDirection;
|
|
31
|
-
readonly gap?: number;
|
|
32
|
-
readonly isCentered?: boolean;
|
|
33
|
-
readonly isFill?: boolean;
|
|
34
|
-
readonly isWrapping?: boolean;
|
|
35
|
-
readonly tag?: keyof HTMLElementTagNameMap;
|
|
36
|
-
}>();
|
|
37
|
-
|
|
38
|
-
defineSlots<{
|
|
39
|
-
default(): VNode[];
|
|
40
|
-
}>();
|
|
41
|
-
</script>
|
package/src/data/filter.ts
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { formatNumber } from '@basmilius/utils';
|
|
2
|
-
import type { FluxFilterDateEntry, FluxFilterDateRangeEntry, FluxFilterDateRangeSpec, FluxFilterDateSpec, FluxFilterEntryMap, FluxFilterOptionAsyncSpec, FluxFilterOptionEntry, FluxFilterOptionHeader, FluxFilterOptionItem, FluxFilterOptionsAsyncSpec, FluxFilterOptionsEntry, FluxFilterOptionSpec, FluxFilterOptionsSpec, FluxFilterRangeEntry, FluxFilterRangeSpec, FluxFilterSpecMap, FluxFilterValueSingle } from '@flux-ui/types';
|
|
3
|
-
import { DateTime } from 'luxon';
|
|
4
|
-
import { useTranslate } from '~flux/components/composable/private';
|
|
5
|
-
import { createLabelForDateRange } from '~flux/components/util';
|
|
6
|
-
import type { FluxTranslate } from './i18n';
|
|
7
|
-
|
|
8
|
-
function parseDate(base: FluxFilterDateSpec): FluxFilterDateEntry {
|
|
9
|
-
return {
|
|
10
|
-
...base,
|
|
11
|
-
type: 'date',
|
|
12
|
-
|
|
13
|
-
async getValueLabel(value): Promise<string | null> {
|
|
14
|
-
if (!DateTime.isDateTime(value)) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return value.toLocaleString({
|
|
19
|
-
day: 'numeric',
|
|
20
|
-
month: 'short',
|
|
21
|
-
year: 'numeric'
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function parseDateRange(base: FluxFilterDateRangeSpec): FluxFilterDateRangeEntry {
|
|
28
|
-
return {
|
|
29
|
-
...base,
|
|
30
|
-
type: 'dateRange',
|
|
31
|
-
|
|
32
|
-
async getValueLabel(value): Promise<string | null> {
|
|
33
|
-
if (!Array.isArray(value) || value.length !== 2) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const [start, end] = value;
|
|
38
|
-
|
|
39
|
-
if (!DateTime.isDateTime(start) || !DateTime.isDateTime(end)) {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return createLabelForDateRange(start, end);
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function parseOption({options, ...base}: FluxFilterOptionSpec): FluxFilterOptionEntry {
|
|
49
|
-
const items = options.filter(isFluxFilterOptionItem);
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
...base,
|
|
53
|
-
type: 'option',
|
|
54
|
-
|
|
55
|
-
async getValueLabel(value): Promise<string | null> {
|
|
56
|
-
return items.find(o => o.value === value)?.label ?? null;
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function parseOptionAsync({fetchOptions, ...base}: FluxFilterOptionAsyncSpec): FluxFilterOptionEntry {
|
|
62
|
-
return {
|
|
63
|
-
...base,
|
|
64
|
-
type: 'option',
|
|
65
|
-
|
|
66
|
-
async getValueLabel(value): Promise<string | null> {
|
|
67
|
-
const items = (await fetchOptions([value])).filter(isFluxFilterOptionItem);
|
|
68
|
-
|
|
69
|
-
return items.find(o => o.value === value)?.label ?? null;
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function parseOptions({options, ...base}: FluxFilterOptionsSpec): FluxFilterOptionsEntry {
|
|
75
|
-
const items = options.filter(isFluxFilterOptionItem);
|
|
76
|
-
const translate = useTranslate();
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
...base,
|
|
80
|
-
type: 'options',
|
|
81
|
-
|
|
82
|
-
async getValueLabel(value): Promise<string | null> {
|
|
83
|
-
if (!Array.isArray(value)) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return generateMultiOptionsLabel(translate, items, value);
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function parseOptionsAsync({fetchOptions, ...base}: FluxFilterOptionsAsyncSpec): FluxFilterOptionsEntry {
|
|
93
|
-
const translate = useTranslate();
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
...base,
|
|
97
|
-
type: 'options',
|
|
98
|
-
|
|
99
|
-
async getValueLabel(value): Promise<string | null> {
|
|
100
|
-
if (!Array.isArray(value)) {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const items = (await fetchOptions(value)).filter(isFluxFilterOptionItem);
|
|
105
|
-
|
|
106
|
-
return generateMultiOptionsLabel(translate, items, value);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function parseRange(base: FluxFilterRangeSpec): FluxFilterRangeEntry {
|
|
112
|
-
return {
|
|
113
|
-
...base,
|
|
114
|
-
type: 'range',
|
|
115
|
-
|
|
116
|
-
async getValueLabel(value): Promise<string | null> {
|
|
117
|
-
if (!value || !Array.isArray(value) || value.length !== 2) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const [lower, upper] = value as number[];
|
|
122
|
-
const formatter = base.formatter ?? formatNumber;
|
|
123
|
-
|
|
124
|
-
return `${formatter(lower!)} – ${formatter(upper!)}`;
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function generateMultiOptionsLabel(translate: FluxTranslate, options: FluxFilterOptionItem[], values: FluxFilterValueSingle[]): string | null {
|
|
130
|
-
const selected = options.filter(o => values.includes(o.value)).length;
|
|
131
|
-
|
|
132
|
-
if (selected <= 0) {
|
|
133
|
-
return null;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (selected === 1) {
|
|
137
|
-
return options.find(o => values.includes(o.value))!.label;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return translate('flux.nSelected', {
|
|
141
|
-
n: selected
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export type FluxFilterParsers = {
|
|
146
|
-
[K in keyof FluxFilterSpecMap]: (spec: FluxFilterSpecMap[K]) => FluxFilterEntryMap[K];
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
export const filterParsers: FluxFilterParsers = {
|
|
150
|
-
date: parseDate,
|
|
151
|
-
dateRange: parseDateRange,
|
|
152
|
-
option: parseOption,
|
|
153
|
-
optionAsync: parseOptionAsync,
|
|
154
|
-
options: parseOptions,
|
|
155
|
-
optionsAsync: parseOptionsAsync,
|
|
156
|
-
range: parseRange
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
export function isFluxFilterOptionHeader(obj: object): obj is FluxFilterOptionHeader {
|
|
160
|
-
return 'title' in obj;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export function isFluxFilterOptionItem(obj: object): obj is FluxFilterOptionItem {
|
|
164
|
-
return 'label' in obj && 'value' in obj;
|
|
165
|
-
}
|