@datagouv/components-next 1.0.2-dev.171 → 1.0.2-dev.173
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/{Datafair.client-B-OG5WtK.js → Datafair.client-DrxHU3d_.js} +1 -1
- package/dist/{ImagePreview.client-D0c-ifUi.js → ImagePreview.client-DHrr-JCM.js} +1 -1
- package/dist/{JsonPreview.client-Dwh9sW9M.js → JsonPreview.client-CvmhvpbB.js} +2 -2
- package/dist/{MapContainer.client-C2AZ7sOB.js → MapContainer.client-9VrKlUPt.js} +2 -2
- package/dist/{PdfPreview.client-8NzNfW8b.js → PdfPreview.client-CiPvfzzR.js} +2 -2
- package/dist/{Pmtiles.client-BFH4rTB7.js → Pmtiles.client-0R3Z5sYM.js} +1 -1
- package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-BOgE441d.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-B0PyOeL6.js} +1 -1
- package/dist/{XmlPreview.client-DMOUO508.js → XmlPreview.client-N2n5j4WI.js} +3 -3
- package/dist/components-next.js +37 -36
- package/dist/components.css +1 -1
- package/dist/{index-C9obT9DJ.js → index-D0JOBDBD.js} +1 -1
- package/dist/{leaflet-src-B4AZU0vr.js → leaflet-src-DxB74Wpp.js} +1 -1
- package/dist/{main-DNoYWfit.js → main-QOs57DKh.js} +4149 -4123
- package/dist/{vue3-xml-viewer.common-Cp7Cu5ME.js → vue3-xml-viewer.common-BnexQtzg.js} +1 -1
- package/package.json +1 -1
- package/src/components/BannerAction.vue +6 -2
- package/src/components/Form/SchemaSelect.vue +2 -0
- package/src/components/SchemaCard.vue +10 -1
- package/src/components/TabularExplorer/TabularExplorer.vue +5 -1
- package/src/composables/useActiveDescendant.ts +5 -0
- package/src/functions/schemas.ts +27 -0
package/package.json
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
>
|
|
11
11
|
<div>
|
|
12
12
|
<div class="text-gray-900">
|
|
13
|
-
|
|
13
|
+
<slot name="title">
|
|
14
|
+
{{ title }}
|
|
15
|
+
</slot>
|
|
14
16
|
</div>
|
|
15
17
|
<div
|
|
16
18
|
v-if="$slots.default"
|
|
@@ -34,7 +36,9 @@ export const bannerActionTypeKey = Symbol() as InjectionKey<'primary' | 'danger'
|
|
|
34
36
|
<script setup lang="ts">
|
|
35
37
|
const props = defineProps<{
|
|
36
38
|
type: 'primary' | 'danger' | 'warning'
|
|
37
|
-
title
|
|
39
|
+
// Optional so the title can be a slot, for instance to make it the toggle of a
|
|
40
|
+
// disclosure whose panel lives in the banner
|
|
41
|
+
title?: string
|
|
38
42
|
}>()
|
|
39
43
|
|
|
40
44
|
provide(bannerActionTypeKey, props.type)
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
:placeholder="t('Tous les schémas')"
|
|
9
9
|
:get-option-id="(s: RegisteredSchema) => s.name"
|
|
10
10
|
:display-value="(s: RegisteredSchema) => s.name"
|
|
11
|
+
:filter="schemaMatchesQuery"
|
|
11
12
|
:multiple="false"
|
|
12
13
|
/>
|
|
13
14
|
</template>
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
import { useTranslation } from '../../composables/useTranslation'
|
|
17
18
|
import { useSelectModelSync } from '../../composables/useSelectModelSync'
|
|
18
19
|
import { useFetch } from '../../functions/api'
|
|
20
|
+
import { schemaMatchesQuery } from '../../functions/schemas'
|
|
19
21
|
import type { RegisteredSchema } from '../../types/schemas'
|
|
20
22
|
import SearchableSelect from './SearchableSelect.vue'
|
|
21
23
|
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
+
:id
|
|
3
4
|
class="p-4 relative border bg-white hover:bg-gray-some"
|
|
4
|
-
:class="{
|
|
5
|
+
:class="{
|
|
6
|
+
'border-gray-default': !selected && !active,
|
|
7
|
+
'border-datagouv': selected && !active,
|
|
8
|
+
'border-blue-outline': active,
|
|
9
|
+
}"
|
|
5
10
|
:role="selectable ? 'option' : undefined"
|
|
11
|
+
:tabindex="selectable ? -1 : undefined"
|
|
6
12
|
:aria-selected="selectable && selected"
|
|
7
13
|
>
|
|
8
14
|
<h3 class="text-base font-bold mb-0 flex items-center gap-1">
|
|
@@ -73,7 +79,10 @@ import { useComponentsConfig } from '../config'
|
|
|
73
79
|
|
|
74
80
|
defineProps<{
|
|
75
81
|
schema: RegisteredSchema
|
|
82
|
+
id?: string
|
|
76
83
|
selectable?: boolean
|
|
84
|
+
// Highlighted by the keyboard inside the listbox, which is not the same as chosen
|
|
85
|
+
active?: boolean
|
|
77
86
|
selected?: boolean
|
|
78
87
|
showLinks?: boolean
|
|
79
88
|
}>()
|
|
@@ -686,6 +686,10 @@ const props = defineProps<{
|
|
|
686
686
|
// The explorer owns them afterwards: later changes to this prop are ignored,
|
|
687
687
|
// so pass a fresh instance (or remount) to reset them.
|
|
688
688
|
initialFilters?: Record<string, ColumnFilters>
|
|
689
|
+
// Sort seeded on mount, e.g. { column: 'Séance', direction: 'desc' }.
|
|
690
|
+
// Same ownership rule as `initialFilters`: the explorer owns it afterwards,
|
|
691
|
+
// and the user can drop it from the active-sort chip.
|
|
692
|
+
initialSort?: SortConfig
|
|
689
693
|
// When set, renders <a> tags inside the specified column cells for native
|
|
690
694
|
// browser UX (hover URL, ctrl+click, middle-click).
|
|
691
695
|
rowHref?: { columns: string[], href: (row: TabularRow) => string }
|
|
@@ -762,7 +766,7 @@ function getColumnType(col: string): ColumnType {
|
|
|
762
766
|
}
|
|
763
767
|
|
|
764
768
|
// Sort & filter state
|
|
765
|
-
const sort = ref<SortConfig | null>(null)
|
|
769
|
+
const sort = ref<SortConfig | null>(props.initialSort ? { ...props.initialSort } : null)
|
|
766
770
|
const filters = ref<Record<string, ColumnFilters>>({ ...props.initialFilters })
|
|
767
771
|
|
|
768
772
|
const PAGE_SIZE = 50
|
|
@@ -60,23 +60,28 @@ export function useActiveDescendant<T extends Option>(options: MaybeRefOrGetter<
|
|
|
60
60
|
|
|
61
61
|
function handleKeyPressForActiveDescendant(key: KeyboardEvent, alreadyMovedDown = false) {
|
|
62
62
|
switch (key.key as CommonKeyboardKeys) {
|
|
63
|
+
// An arrow that moves the active option must not also scroll the page behind it
|
|
63
64
|
case 'ArrowDown':
|
|
64
65
|
if (direction === 'vertical' && !alreadyMovedDown && !key.altKey) {
|
|
66
|
+
key.preventDefault()
|
|
65
67
|
activateNextOption()
|
|
66
68
|
}
|
|
67
69
|
break
|
|
68
70
|
case 'ArrowUp':
|
|
69
71
|
if (direction === 'vertical') {
|
|
72
|
+
key.preventDefault()
|
|
70
73
|
activatePreviousOption()
|
|
71
74
|
}
|
|
72
75
|
break
|
|
73
76
|
case 'ArrowLeft':
|
|
74
77
|
if (direction === 'horizontal') {
|
|
78
|
+
key.preventDefault()
|
|
75
79
|
activatePreviousOption()
|
|
76
80
|
}
|
|
77
81
|
break
|
|
78
82
|
case 'ArrowRight':
|
|
79
83
|
if (direction === 'horizontal' && !alreadyMovedDown && !key.altKey) {
|
|
84
|
+
key.preventDefault()
|
|
80
85
|
activateNextOption()
|
|
81
86
|
}
|
|
82
87
|
break
|
package/src/functions/schemas.ts
CHANGED
|
@@ -31,6 +31,33 @@ export function getSchemaVersion(schema: RegisteredSchema | null) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Accents and separators must not stand between a query and a schema: people type
|
|
35
|
+
// "lave linge" for « Lave-linge », or « reparabilite » without its accents
|
|
36
|
+
function normalizeForSearch(value: string): string {
|
|
37
|
+
return value
|
|
38
|
+
.toLowerCase()
|
|
39
|
+
.normalize('NFD')
|
|
40
|
+
.replace(/\p{Diacritic}/gu, '')
|
|
41
|
+
.replace(/[^a-z0-9]+/g, ' ')
|
|
42
|
+
.trim()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The name is searched along with the title and the description: it is the identifier
|
|
46
|
+
// people know and paste, such as `etalab/indice-durabilite-lave-linge`
|
|
47
|
+
const searchableText = (schema: RegisteredSchema) => normalizeForSearch(`${schema.name} ${schema.title ?? ''} ${schema.description ?? ''}`)
|
|
48
|
+
|
|
49
|
+
const queryTokens = (query: string) => normalizeForSearch(query).split(' ').filter(Boolean)
|
|
50
|
+
|
|
51
|
+
export function schemaMatchesQuery(schema: RegisteredSchema, query: string): boolean {
|
|
52
|
+
// A query made only of punctuation holds no word to match. Callers short-circuit the
|
|
53
|
+
// empty query, so matching everything here would only ever answer that case.
|
|
54
|
+
const tokens = queryTokens(query)
|
|
55
|
+
if (!tokens.length) return false
|
|
56
|
+
|
|
57
|
+
const haystack = searchableText(schema)
|
|
58
|
+
return tokens.every(token => haystack.includes(token))
|
|
59
|
+
}
|
|
60
|
+
|
|
34
61
|
export function findSchemaInCatalog(catalog: Array<RegisteredSchema>, schema: Schema | null): RegisteredSchema | null {
|
|
35
62
|
if (!schema) return null
|
|
36
63
|
return catalog.find(registeredSchema => schema.name === registeredSchema.name) || null
|