@datagouv/components-next 1.0.2-dev.195 → 1.0.2-dev.197

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.
Files changed (22) hide show
  1. package/dist/{Datafair.client-w30urimy.js → Datafair.client--IZYDcc-.js} +1 -1
  2. package/dist/{ImagePreview.client-DVAf75eI.js → ImagePreview.client-g7FMZPMq.js} +1 -1
  3. package/dist/{JsonPreview.client-BO4FYlVq.js → JsonPreview.client-BdB0FOO1.js} +2 -2
  4. package/dist/{MapContainer.client-D5ZOWzlJ.js → MapContainer.client-BT-vDpwp.js} +2 -2
  5. package/dist/{PdfPreview.client-Cal_OaFX.js → PdfPreview.client-BXr2vkwe.js} +2 -2
  6. package/dist/{Pmtiles.client-DWfTeeOk.js → Pmtiles.client-C5imIHi-.js} +1 -1
  7. package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-CNDEB-3x.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-CDL_M0JO.js} +1 -1
  8. package/dist/{XmlPreview.client-C8GN6y1u.js → XmlPreview.client-xEhDGqxd.js} +3 -3
  9. package/dist/components-next.js +1 -1
  10. package/dist/components.css +1 -1
  11. package/dist/{index-WRb99DNu.js → index-Bh0u3y-Z.js} +4504 -4306
  12. package/dist/{leaflet-src-DJeNmzLc.js → leaflet-src-CUSMMz-a.js} +34 -34
  13. package/dist/{main-B3IzELg_.js → main-J2uwmRv6.js} +10034 -9689
  14. package/dist/{vue3-xml-viewer.common-AEbzQxXP.js → vue3-xml-viewer.common-IPjY1Ugx.js} +16 -16
  15. package/package.json +1 -1
  16. package/src/components/LoadingBlock.vue +4 -1
  17. package/src/components/Pagination.vue +2 -4
  18. package/src/components/Search/GlobalSearch.vue +9 -6
  19. package/src/components/TabularExplorer/types.ts +15 -12
  20. package/src/components/TabularExplorer/useColumnMetadata.ts +1 -1
  21. package/src/functions/charts.ts +2 -2
  22. package/src/functions/scroll.ts +20 -0
@@ -1,24 +1,24 @@
1
- import { g as Ke } from "./main-B3IzELg_.js";
1
+ import { g as Ke } from "./main-J2uwmRv6.js";
2
2
  import We from "vue";
3
- function Fe($, K) {
3
+ function Fe(I, K) {
4
4
  for (var V = 0; V < K.length; V++) {
5
5
  const p = K[V];
6
6
  if (typeof p != "string" && !Array.isArray(p)) {
7
7
  for (const X in p)
8
- if (X !== "default" && !(X in $)) {
8
+ if (X !== "default" && !(X in I)) {
9
9
  const _ = Object.getOwnPropertyDescriptor(p, X);
10
- _ && Object.defineProperty($, X, _.get ? _ : {
10
+ _ && Object.defineProperty(I, X, _.get ? _ : {
11
11
  enumerable: !0,
12
12
  get: () => p[X]
13
13
  });
14
14
  }
15
15
  }
16
16
  }
17
- return Object.freeze(Object.defineProperty($, Symbol.toStringTag, { value: "Module" }));
17
+ return Object.freeze(Object.defineProperty(I, Symbol.toStringTag, { value: "Module" }));
18
18
  }
19
19
  var Y = { exports: {} }, ee;
20
20
  function ze() {
21
- return ee || (ee = 1, (function($) {
21
+ return ee || (ee = 1, (function(I) {
22
22
  (function() {
23
23
  var K = {
24
24
  /***/
@@ -426,7 +426,7 @@ function ze() {
426
426
  default: function() {
427
427
  return (
428
428
  /* binding */
429
- $e
429
+ Ie
430
430
  );
431
431
  }
432
432
  }), typeof window < "u") {
@@ -466,7 +466,7 @@ function ze() {
466
466
  class: "bracket"
467
467
  }, ">", -1));
468
468
  function G(o, v, g, E, h, b) {
469
- const y = (0, e.resolveComponent)("CaretDown"), S = (0, e.resolveComponent)("CaretRight"), I = (0, e.resolveComponent)("XmlElementName"), Q = (0, e.resolveComponent)("XmlAttributeLine"), q = (0, e.resolveComponent)("XmlElement", !0), B = (0, e.resolveComponent)("XmlElementContent"), je = (0, e.resolveComponent)("XmlCDataSection"), Ue = (0, e.resolveComponent)("XmlRemark");
469
+ const y = (0, e.resolveComponent)("CaretDown"), S = (0, e.resolveComponent)("CaretRight"), $ = (0, e.resolveComponent)("XmlElementName"), Q = (0, e.resolveComponent)("XmlAttributeLine"), q = (0, e.resolveComponent)("XmlElement", !0), B = (0, e.resolveComponent)("XmlElementContent"), je = (0, e.resolveComponent)("XmlCDataSection"), Ue = (0, e.resolveComponent)("XmlRemark");
470
470
  return (0, e.openBlock)(), (0, e.createElementBlock)("div", r, [(0, e.createElementVNode)("div", null, [o.selfClosing ? (0, e.createCommentVNode)("", !0) : ((0, e.openBlock)(), (0, e.createElementBlock)(e.Fragment, {
471
471
  key: 0
472
472
  }, [o.collapsed ? ((0, e.openBlock)(), (0, e.createBlock)(S, {
@@ -477,7 +477,7 @@ function ze() {
477
477
  key: 0,
478
478
  class: "caret",
479
479
  onClick: o.toggleCollapsed
480
- }, null, 8, ["onClick"]))], 64)), u, (0, e.createVNode)(I, {
480
+ }, null, 8, ["onClick"]))], 64)), u, (0, e.createVNode)($, {
481
481
  class: "clickable",
482
482
  name: o.name,
483
483
  onClick: o.toggleCollapsed
@@ -496,7 +496,7 @@ function ze() {
496
496
  }, null, 8, ["cdataSection"]))), 128)), ((0, e.openBlock)(!0), (0, e.createElementBlock)(e.Fragment, null, (0, e.renderList)(o.remarks, (L, N) => ((0, e.openBlock)(), (0, e.createBlock)(Ue, {
497
497
  key: `r${N}`,
498
498
  remark: L
499
- }, null, 8, ["remark"]))), 128))])])), !o.selfClosing && !o.collapsed ? ((0, e.openBlock)(), (0, e.createElementBlock)("div", w, [O, (0, e.createVNode)(I, {
499
+ }, null, 8, ["remark"]))), 128))])])), !o.selfClosing && !o.collapsed ? ((0, e.openBlock)(), (0, e.createElementBlock)("div", w, [O, (0, e.createVNode)($, {
500
500
  name: o.name,
501
501
  closing: !0
502
502
  }, null, 8, ["name"]), f])) : (0, e.createCommentVNode)("", !0)]);
@@ -549,8 +549,8 @@ function ze() {
549
549
  var c = /* @__PURE__ */ (0, M.A)(d, [["render", m], ["__scopeId", "data-v-75f773a5"]]);
550
550
  function D(o, v, g, E, h, b) {
551
551
  const y = (0, e.resolveComponent)("XmlAttribute");
552
- return (0, e.openBlock)(), (0, e.createElementBlock)("span", null, [((0, e.openBlock)(!0), (0, e.createElementBlock)(e.Fragment, null, (0, e.renderList)(o.attributes, (S, I) => ((0, e.openBlock)(), (0, e.createBlock)(y, {
553
- key: I,
552
+ return (0, e.openBlock)(), (0, e.createElementBlock)("span", null, [((0, e.openBlock)(!0), (0, e.createElementBlock)(e.Fragment, null, (0, e.renderList)(o.attributes, (S, $) => ((0, e.openBlock)(), (0, e.createBlock)(y, {
553
+ key: $,
554
554
  attribute: S
555
555
  }, null, 8, ["attribute"]))), 128))]);
556
556
  }
@@ -705,12 +705,12 @@ function ze() {
705
705
  node: Element
706
706
  },
707
707
  setup(o) {
708
- const v = (0, e.ref)(!1), g = (0, e.computed)(() => o.node.nodeName), E = (0, e.computed)(() => Array.from(o.node.childNodes)), h = (0, e.computed)(() => E.value && E.value.filter((B) => B.nodeType === 1)), b = (0, e.computed)(() => E.value && E.value.filter((B) => B.nodeType === 3)), y = (0, e.computed)(() => E.value && E.value.filter((B) => B.nodeType === 4)), S = (0, e.computed)(() => E.value && E.value.filter((B) => B.nodeType === 8)), I = (0, e.computed)(() => o.node.attributes && Array.from(o.node.attributes) || []), Q = !h.value.length && !b.value.length && !y.value.length && !S.value.length;
708
+ const v = (0, e.ref)(!1), g = (0, e.computed)(() => o.node.nodeName), E = (0, e.computed)(() => Array.from(o.node.childNodes)), h = (0, e.computed)(() => E.value && E.value.filter((B) => B.nodeType === 1)), b = (0, e.computed)(() => E.value && E.value.filter((B) => B.nodeType === 3)), y = (0, e.computed)(() => E.value && E.value.filter((B) => B.nodeType === 4)), S = (0, e.computed)(() => E.value && E.value.filter((B) => B.nodeType === 8)), $ = (0, e.computed)(() => o.node.attributes && Array.from(o.node.attributes) || []), Q = !h.value.length && !b.value.length && !y.value.length && !S.value.length;
709
709
  return {
710
710
  name: g,
711
711
  childElements: h,
712
712
  childContents: b,
713
- attributes: I,
713
+ attributes: $,
714
714
  cdataSections: y,
715
715
  remarks: S,
716
716
  selfClosing: Q,
@@ -744,8 +744,8 @@ function ze() {
744
744
  rootNode: g
745
745
  };
746
746
  }
747
- }), Ve = /* @__PURE__ */ (0, M.A)(Ne, [["render", t]]), Ie = Ve, $e = Ie;
748
- })(), $.exports = X;
747
+ }), Ve = /* @__PURE__ */ (0, M.A)(Ne, [["render", t]]), $e = Ve, Ie = $e;
748
+ })(), I.exports = X;
749
749
  })();
750
750
  })(Y)), Y.exports;
751
751
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datagouv/components-next",
3
- "version": "1.0.2-dev.195",
3
+ "version": "1.0.2-dev.197",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -1,8 +1,11 @@
1
1
  <template>
2
2
  <div class="relative">
3
3
  <div :class="{ 'opacity-50 min-h-64': loading }">
4
+ <!-- Keep the previous content while reloading, dimmed under the loader:
5
+ dropping it collapses the page height, which makes the browser clamp
6
+ the scroll and throws the reader back to the top. -->
4
7
  <slot
5
- v-if="!loading && !hasError && data"
8
+ v-if="!hasError && data"
6
9
  :data="data"
7
10
  />
8
11
  <slot
@@ -104,6 +104,7 @@ import { computed, useTemplateRef } from 'vue'
104
104
  import { useRoute } from 'vue-router'
105
105
  import { useTranslation } from '../composables/useTranslation'
106
106
  import { clampPage, getVisiblePages } from '../functions/paginate'
107
+ import { scrollToBlockTop } from '../functions/scroll'
107
108
 
108
109
  type Props = {
109
110
  /**
@@ -141,10 +142,7 @@ const nav = useTemplateRef('navRef')
141
142
  function change(index: number) {
142
143
  emit('change', index)
143
144
 
144
- if (!nav.value || !nav.value.parentElement) return
145
-
146
- nav.value.parentElement.style.scrollMarginTop = '100px'
147
- nav.value.parentElement.scrollIntoView({ behavior: 'smooth', block: 'start' })
145
+ scrollToBlockTop(nav.value?.parentElement)
148
146
  }
149
147
 
150
148
  function onClick(index: number) {
@@ -6,7 +6,6 @@
6
6
  >
7
7
  <div
8
8
  v-if="!hideSearchInput"
9
- ref="search"
10
9
  class="flex flex-wrap items-center justify-between"
11
10
  data-cy="search"
12
11
  >
@@ -357,6 +356,7 @@
357
356
  <script setup lang="ts">
358
357
  import { computed, provide, shallowReactive, useSlots, watch, useTemplateRef, type Component, type Ref } from 'vue'
359
358
  import { useRouteQuery } from '@vueuse/router'
359
+ import { useRoute } from 'vue-router'
360
360
  import { RiBookShelfLine, RiBuilding2Line, RiCloseCircleLine, RiDatabase2Line, RiLightbulbLine, RiLineChartLine, RiRssLine, RiTerminalLine } from '@remixicon/vue'
361
361
  import magnifyingGlassSrc from '../../../assets/illustrations/magnifying_glass.svg?url'
362
362
  import { useTranslation } from '../../composables/useTranslation'
@@ -365,6 +365,7 @@ import { configKey, forEachActiveCustomFilter, isCustomFilterActive, searchFilte
365
365
  import { useStableQueryParams } from '../../composables/useStableQueryParams'
366
366
  import { useComponentsConfig } from '../../config'
367
367
  import { useFetch } from '../../functions/api'
368
+ import { scrollToBlockTop } from '../../functions/scroll'
368
369
  import type { AsyncDataRequestStatus } from '../../functions/api.types'
369
370
  import type { Dataset } from '../../types/datasets'
370
371
  import type { Dataservice } from '../../types/dataservices'
@@ -423,6 +424,7 @@ if (!currentType.value) currentType.value = configKey(props.config[0] ?? { class
423
424
 
424
425
  const { t } = useTranslation()
425
426
  const componentsConfig = useComponentsConfig()
427
+ const route = useRoute()
426
428
 
427
429
  // Custom filter registry for useSearchFilter composable
428
430
  const customFilterRegistry = shallowReactive(new Map<string, CustomFilterEntry>())
@@ -797,14 +799,15 @@ function getFacets(key: string): FacetItem[] | undefined {
797
799
  }
798
800
 
799
801
  // Scroll handling
800
- const searchRef = useTemplateRef('search')
802
+ const resultsRef = useTemplateRef('results')
801
803
 
802
- function scrollToTop() {
803
- searchRef.value?.scrollIntoView({ behavior: 'smooth' })
804
- }
804
+ // Every criteria lives in the URL, custom filters included, so watching the
805
+ // query covers them all: whenever the result list is replaced, bring its top
806
+ // back into view rather than leaving the reader in the middle of a list they
807
+ // have not seen yet.
808
+ watch(() => route.query, () => scrollToBlockTop(resultsRef.value))
805
809
 
806
810
  function changePage(newPage: number) {
807
811
  page.value = newPage
808
- scrollToTop()
809
812
  }
810
813
  </script>
@@ -24,25 +24,28 @@ export type TabularProfileResponse = {
24
24
  indexes: null
25
25
  }
26
26
 
27
+ // Only CSV resources go through csv-detective: for the other formats the API
28
+ // indexes (parquet…), the profile is reduced to the column names, their types
29
+ // and the row count. Everything csv-detective produces is therefore optional.
27
30
  export type TabularProfile = {
28
31
  header: string[]
29
32
  columns: Record<string, TabularColumnInfo>
30
- formats: Record<string, string[]>
31
- profile: Record<string, TabularColumnProfile>
32
- encoding: string
33
- separator: string
34
- categorical: string[]
35
33
  total_lines: number
36
- nb_duplicates: number
37
- columns_fields: Record<string, TabularColumnInfo>
38
- columns_labels: Record<string, TabularColumnInfo>
39
- header_row_idx: number
40
- heading_columns: number
41
- trailing_columns: number
34
+ formats?: Record<string, string[]>
35
+ profile?: Record<string, TabularColumnProfile>
36
+ encoding?: string
37
+ separator?: string
38
+ categorical?: string[]
39
+ nb_duplicates?: number
40
+ columns_fields?: Record<string, TabularColumnInfo>
41
+ columns_labels?: Record<string, TabularColumnInfo>
42
+ header_row_idx?: number
43
+ heading_columns?: number
44
+ trailing_columns?: number
42
45
  }
43
46
 
44
47
  export type TabularColumnInfo = {
45
- score: number
48
+ score?: number
46
49
  format: string
47
50
  python_type: string
48
51
  }
@@ -38,7 +38,7 @@ export function useColumnMetadata(
38
38
  if (!profile) return 'text'
39
39
  const colInfo = profile.columns[col]
40
40
  if (!colInfo) return 'text'
41
- return resolveColumnType(colInfo, profile.categorical.includes(col))
41
+ return resolveColumnType(colInfo, profile.categorical?.includes(col) ?? false)
42
42
  }
43
43
 
44
44
  const columnTypesMap = computed<Record<string, ColumnType>>(() => {
@@ -72,13 +72,13 @@ export function toChartApi(chartForm: ChartForm): ChartForApi {
72
72
  export function buildColumnsFromProfile(profile: { profile: TabularProfile }): Array<ColumnDefinition> {
73
73
  return profile.profile.header.map((name) => {
74
74
  const colInfo = profile.profile.columns[name]
75
- const isCategorical = profile.profile.categorical.includes(name)
75
+ const isCategorical = profile.profile.categorical?.includes(name) ?? false
76
76
  // The chart stack only branches on 'number' and 'date' (continuous axis,
77
77
  // aggregatable series, time formatting): it has no notion of a year column,
78
78
  // and on an axis a year is a number.
79
79
  const resolvedType = resolveColumnType(colInfo ?? { python_type: 'unknown', format: undefined }, isCategorical)
80
80
  const colType = resolvedType === 'year' ? 'number' : resolvedType
81
- const colProfile = profile.profile.profile[name]
81
+ const colProfile = profile.profile.profile?.[name]
82
82
  return {
83
83
  name,
84
84
  type: colType,
@@ -0,0 +1,20 @@
1
+ // Leaves room for the sticky elements sitting at the top of the viewport.
2
+ const SCROLL_MARGIN = 100
3
+
4
+ /**
5
+ * Bring the top of a block back into view after its content changed (paging,
6
+ * searching, filtering), so the reader restarts at the first result.
7
+ *
8
+ * Does nothing when the top of the block is already on screen: aligning the
9
+ * viewport on a block the reader is already looking at moves the page under
10
+ * them for no reason.
11
+ */
12
+ export function scrollToBlockTop(block: HTMLElement | null | undefined) {
13
+ if (!block) return
14
+
15
+ const { top } = block.getBoundingClientRect()
16
+ if (top >= 0 && top <= window.innerHeight) return
17
+
18
+ block.style.scrollMarginTop = `${SCROLL_MARGIN}px`
19
+ block.scrollIntoView({ behavior: 'smooth', block: 'start' })
20
+ }