@datawheel/data-explorer 1.4.0 → 1.4.2

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/main.d.mts CHANGED
@@ -463,6 +463,7 @@ interface PropertyItem extends QueryParamsItem {
463
463
  }
464
464
 
465
465
  type Formatter = (value: number | null, locale?: string) => string;
466
+ type DrilldownFormatter = (value: string | null, locale?: string) => string;
466
467
  interface PanelDescriptor {
467
468
  key: string;
468
469
  label: string;
@@ -1146,6 +1147,10 @@ declare function ExplorerComponent<Locale extends string>(props: {
1146
1147
  * that are displayed next to the value.
1147
1148
  * */
1148
1149
  idFormatters?: Record<string, Formatter>;
1150
+ /**
1151
+ * Defines an index of formatter functions available for drilldowns.
1152
+ * */
1153
+ drilldownFormatters?: Record<string, DrilldownFormatter>;
1149
1154
  /**
1150
1155
  * Defines an alternative height for the component structure.
1151
1156
  * @default "100vh"
@@ -1333,6 +1338,7 @@ interface SettingsContextProps {
1333
1338
  defaultMembersFilter: "id" | "name" | "any";
1334
1339
  formatters: Record<string, Formatter>;
1335
1340
  idFormatters: Record<string, Formatter>;
1341
+ drilldownFormatters: Record<string, DrilldownFormatter>;
1336
1342
  previewLimit: number;
1337
1343
  panels: PanelDescriptor[];
1338
1344
  paginationConfig: Pagination;
package/dist/main.mjs CHANGED
@@ -600,6 +600,7 @@ function SettingsProvider(props) {
600
600
  defaultMembersFilter: props.defaultMembersFilter || "id",
601
601
  formatters: props.formatters || {},
602
602
  idFormatters: props.idFormatters || {},
603
+ drilldownFormatters: props.drilldownFormatters || {},
603
604
  panels: props.panels,
604
605
  previewLimit: props.previewLimit || 50,
605
606
  paginationConfig: (_a = props.pagination) != null ? _a : { rowsLimits: [100, 300, 500, 1e3], defaultLimit: 100 },
@@ -713,6 +714,10 @@ function useidFormatters() {
713
714
  const { idFormatters } = useSettings();
714
715
  return { idFormatters };
715
716
  }
717
+ function useDrilldownFormatters() {
718
+ const { drilldownFormatters } = useSettings();
719
+ return { drilldownFormatters };
720
+ }
716
721
 
717
722
  // src/utils/structs.ts
718
723
  function buildQuery(props) {
@@ -3318,6 +3323,7 @@ function useTable({
3318
3323
  const { translate: t } = useTranslation();
3319
3324
  const { getFormat, getFormatter } = useFormatter();
3320
3325
  const { idFormatters } = useidFormatters();
3326
+ const { drilldownFormatters } = useDrilldownFormatters();
3321
3327
  const { sortKey, sortDir } = useSelector$1(selectSortingParams);
3322
3328
  const theme = useMantineTheme();
3323
3329
  const isSmallerThanMd = useMediaQuery(
@@ -3471,6 +3477,8 @@ function useTable({
3471
3477
  const row = cell.row;
3472
3478
  const cellId = row.original[`${cell.column.id} ID`];
3473
3479
  const idFormatter = idFormatters[`${keyCol.localeLabel} ID`];
3480
+ const drilldownFormatter = drilldownFormatters[`${keyCol.localeLabel}`] || drilldownFormatters[`${entity.name}`];
3481
+ const formattedValue = drilldownFormatter ? drilldownFormatter(cellValue, locale) : cellValue;
3474
3482
  return /* @__PURE__ */ React15__default.createElement(Flex, { justify: "space-between", sx: { width: "100%", maxWidth: 400 }, gap: "sm" }, /* @__PURE__ */ React15__default.createElement(
3475
3483
  Text,
3476
3484
  {
@@ -3481,7 +3489,7 @@ function useTable({
3481
3489
  textOverflow: "ellipsis"
3482
3490
  }
3483
3491
  },
3484
- cellValue
3492
+ formattedValue
3485
3493
  ), /* @__PURE__ */ React15__default.createElement(Box, null, cellId && /* @__PURE__ */ React15__default.createElement(Text, { color: "dimmed" }, idFormatter ? idFormatter(cellId) : cellId)));
3486
3494
  }
3487
3495
  };
@@ -3782,12 +3790,13 @@ var MultiFilter = ({ header }) => {
3782
3790
  const { translate: t } = useTranslation();
3783
3791
  const cutItems = useSelector$1(selectCutItems);
3784
3792
  const drilldownItems = useSelector$1(selectDrilldownItems);
3785
- useSelector$1(selectLocale);
3786
- header.column.id;
3793
+ const locale = useSelector$1(selectLocale);
3794
+ const label = header.column.id;
3787
3795
  const localeLabel = header.column.columnDef.header;
3788
3796
  const drilldown = drilldownItems.find((d) => d.level === header.column.id);
3789
3797
  const actions2 = useActions();
3790
3798
  const { idFormatters } = useidFormatters();
3799
+ const { drilldownFormatters } = useDrilldownFormatters();
3791
3800
  const navigate = useNavigate();
3792
3801
  const debouncedUpdateUrl = useMemo(
3793
3802
  () => debounce((query2) => {
@@ -3831,11 +3840,13 @@ var MultiFilter = ({ header }) => {
3831
3840
  value: cut.members || [],
3832
3841
  data: drilldown.members.map((m) => {
3833
3842
  const idFormatter = idFormatters[`${localeLabel} ID`];
3843
+ const drilldownFormatter = drilldownFormatters[`${localeLabel}`] || drilldownFormatters[`${label}`];
3834
3844
  const formattedKey = idFormatter ? idFormatter(m.key) : m.key;
3835
3845
  const key = formattedKey ? `(${formattedKey})` : formattedKey;
3846
+ const formattedCaption = drilldownFormatter ? drilldownFormatter(m.caption || m.key, locale.code) : m.caption;
3836
3847
  return {
3837
3848
  value: `${m.key}`,
3838
- label: m.caption ? `${m.caption} ${key}` : `${key}`
3849
+ label: formattedCaption ? `${formattedCaption} ${key}` : `${key}`
3839
3850
  };
3840
3851
  }),
3841
3852
  clearButtonProps: { "aria-label": "Clear selection" },
@@ -4008,6 +4019,7 @@ function LevelItem({
4008
4019
  const drilldowns = useSelector$1(selectDrilldownMap);
4009
4020
  useSelector$1(selectDrilldownItems);
4010
4021
  const { idFormatters } = useidFormatters();
4022
+ const { drilldownFormatters } = useDrilldownFormatters();
4011
4023
  const label = useMemo(() => {
4012
4024
  const captions = [
4013
4025
  getCaption(dimension, locale),
@@ -4116,11 +4128,13 @@ function LevelItem({
4116
4128
  value: (cut == null ? void 0 : cut.members) || [],
4117
4129
  data: currentDrilldown.members.map((m) => {
4118
4130
  const idFormatter = idFormatters[`${label} ID`];
4131
+ const drilldownFormatter = drilldownFormatters[`${label}`];
4119
4132
  const formattedKey = idFormatter ? idFormatter(m.key) : m.key;
4120
4133
  const key = formattedKey ? `(${formattedKey})` : formattedKey;
4134
+ const formattedCaption = drilldownFormatter ? drilldownFormatter(m.caption || m.key, locale) : m.caption;
4121
4135
  return {
4122
4136
  value: `${m.key}`,
4123
- label: m.caption ? `${m.caption} ${key}` : `${key}`
4137
+ label: formattedCaption ? `${formattedCaption} ${key}` : `${key}`
4124
4138
  };
4125
4139
  }),
4126
4140
  clearable: true,
@@ -4797,10 +4811,15 @@ function useBuildGraph(locale) {
4797
4811
  const hide = getAnnotation(item, "hide_in_ui", locale);
4798
4812
  if (!yn(hide)) {
4799
4813
  graph2.addNode(topic);
4800
- graph2.addNode(subtopic);
4801
4814
  graph2.addNode(name4);
4802
- graph2.addEdge(topic, subtopic);
4803
- graph2.addEdge(subtopic, name4);
4815
+ if (subtopic) {
4816
+ const uniqueSubtopic = `${topic} - ${subtopic}`;
4817
+ graph2.addNode(uniqueSubtopic);
4818
+ graph2.addEdge(topic, uniqueSubtopic);
4819
+ graph2.addEdge(uniqueSubtopic, name4);
4820
+ } else {
4821
+ graph2.addEdge(topic, name4);
4822
+ }
4804
4823
  if (topic_order) {
4805
4824
  graph2.addTopicOrder(topic, topic_order);
4806
4825
  }
@@ -5416,8 +5435,16 @@ function useAccordionValue(key, locale) {
5416
5435
  const [value, setValue] = useState(null);
5417
5436
  useEffect(() => {
5418
5437
  if (selectedItem) {
5419
- const value2 = getAnnotation(selectedItem, key, locale);
5420
- setValue(`${key}-${value2}`);
5438
+ const topic = getAnnotation(selectedItem, "topic", locale);
5439
+ const subtopic = getAnnotation(selectedItem, "subtopic", locale);
5440
+ if (key === "subtopic" && subtopic) {
5441
+ setValue(`${key}-${topic} - ${subtopic}`);
5442
+ } else if (key === "topic") {
5443
+ setValue(`${key}-${topic}`);
5444
+ } else {
5445
+ const val = getAnnotation(selectedItem, key, locale);
5446
+ setValue(`${key}-${val}`);
5447
+ }
5421
5448
  }
5422
5449
  }, [key, selectedItem, locale]);
5423
5450
  return { value, setValue };
@@ -5458,19 +5485,18 @@ function RootAccordions({ items, sortItems, graph, locale, selectedItem, sortLoc
5458
5485
  const sortItem = sortItems.find(
5459
5486
  (topic) => graph.topicOrder[topic] === graph.topicOrder[item]
5460
5487
  ) || item;
5461
- return /* @__PURE__ */ React15__default.createElement(Accordion.Item, { value: `topic-${item}`, key: `topic-${item}` }, /* @__PURE__ */ React15__default.createElement(AccordionControl, null, item), /* @__PURE__ */ React15__default.createElement(Accordion.Panel, null, /* @__PURE__ */ React15__default.createElement(
5462
- SubtopicAccordion,
5488
+ return /* @__PURE__ */ React15__default.createElement(Accordion.Item, { value: `topic-${item}`, key: `topic-${item}` }, /* @__PURE__ */ React15__default.createElement(AccordionControl, null, item), /* @__PURE__ */ React15__default.createElement(Accordion.Panel, null, /* @__PURE__ */ React15__default.createElement("div", { style: { display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React15__default.createElement(
5489
+ TopicChildren,
5463
5490
  {
5464
5491
  graph,
5465
5492
  parent: item,
5466
5493
  sortParent: sortItem,
5467
5494
  items: graph.adjList[item],
5468
- key: item,
5469
5495
  locale,
5470
5496
  sortLocale,
5471
5497
  selectedItem
5472
5498
  }
5473
- )));
5499
+ ))));
5474
5500
  })
5475
5501
  );
5476
5502
  }
@@ -5514,6 +5540,56 @@ function CubeButton({
5514
5540
  table != null ? table : item
5515
5541
  );
5516
5542
  }
5543
+ function TopicChildren({
5544
+ items,
5545
+ graph,
5546
+ parent,
5547
+ sortParent,
5548
+ selectedItem,
5549
+ locale,
5550
+ sortLocale
5551
+ }) {
5552
+ const { directCubes, subtopics } = useMemo(() => {
5553
+ const cubes = [];
5554
+ const folders = [];
5555
+ items.forEach((item) => {
5556
+ const cube = graph.items.find((c) => c.name === item);
5557
+ if (cube) {
5558
+ cubes.push(item);
5559
+ } else {
5560
+ folders.push(item);
5561
+ }
5562
+ });
5563
+ return { directCubes: cubes, subtopics: folders };
5564
+ }, [items, graph]);
5565
+ return /* @__PURE__ */ React15__default.createElement(React15__default.Fragment, null, directCubes.sort((a, b) => {
5566
+ const aLabel = graph.getName(a, sortLocale);
5567
+ const bLabel = graph.getName(b, sortLocale);
5568
+ return aLabel.localeCompare(bLabel, sortLocale, { sensitivity: "base" });
5569
+ }).map((cube, index) => /* @__PURE__ */ React15__default.createElement(
5570
+ CubeButton,
5571
+ {
5572
+ key: `direct-${cube}-${index}`,
5573
+ graph,
5574
+ item: cube,
5575
+ locale,
5576
+ sortLocale,
5577
+ selectedItem,
5578
+ parent: ""
5579
+ }
5580
+ )), subtopics.length > 0 && /* @__PURE__ */ React15__default.createElement(
5581
+ SubtopicAccordion,
5582
+ {
5583
+ items: subtopics,
5584
+ graph,
5585
+ parent,
5586
+ sortParent,
5587
+ selectedItem,
5588
+ locale,
5589
+ sortLocale
5590
+ }
5591
+ ));
5592
+ }
5517
5593
  function SubtopicAccordion({
5518
5594
  items,
5519
5595
  graph,
@@ -5551,29 +5627,32 @@ function SubtopicAccordion({
5551
5627
  })
5552
5628
  },
5553
5629
  [...items].sort((a, b) => {
5630
+ const aName = a.split(" - ").pop();
5631
+ const bName = b.split(" - ").pop();
5554
5632
  const aLabel = graph.items.find(
5555
- (cube) => getAnnotation(cube, "topic", locale) === parent && getAnnotation(cube, "subtopic", locale) === a
5633
+ (cube) => getAnnotation(cube, "topic", locale) === parent && getAnnotation(cube, "subtopic", locale) === aName
5556
5634
  );
5557
5635
  const bLabel = graph.items.find(
5558
- (cube) => getAnnotation(cube, "topic", locale) === parent && getAnnotation(cube, "subtopic", locale) === b
5636
+ (cube) => getAnnotation(cube, "topic", locale) === parent && getAnnotation(cube, "subtopic", locale) === bName
5559
5637
  );
5560
- const aSort = aLabel ? getAnnotation(aLabel, "subtopic", sortLocale) || a : a;
5561
- const bSort = bLabel ? getAnnotation(bLabel, "subtopic", sortLocale) || b : b;
5638
+ const aSort = (aLabel ? getAnnotation(aLabel, "subtopic", sortLocale) : null) || aName || "";
5639
+ const bSort = (bLabel ? getAnnotation(bLabel, "subtopic", sortLocale) : null) || bName || "";
5562
5640
  return aSort.localeCompare(bSort, sortLocale, { sensitivity: "base" });
5563
5641
  }).map((item, index) => {
5564
5642
  let sortSubtopic = item;
5643
+ const itemName = item.split(" - ").pop();
5565
5644
  if (sortParent && item) {
5566
5645
  const hasCubeInLocale = graph.items.some(
5567
- (cube) => getAnnotation(cube, "topic", locale) === parent && getAnnotation(cube, "subtopic", locale) === item
5646
+ (cube) => getAnnotation(cube, "topic", locale) === parent && getAnnotation(cube, "subtopic", locale) === itemName
5568
5647
  );
5569
5648
  if (hasCubeInLocale) {
5570
5649
  const matchingCube = graph.items.find(
5571
- (cube) => getAnnotation(cube, "topic", sortLocale) === sortParent && getAnnotation(cube, "subtopic", locale) === item
5650
+ (cube) => getAnnotation(cube, "topic", sortLocale) === sortParent && getAnnotation(cube, "subtopic", locale) === itemName
5572
5651
  );
5573
5652
  if (matchingCube) {
5574
5653
  const annotatedSubtopic = getAnnotation(matchingCube, "subtopic", sortLocale);
5575
5654
  if (annotatedSubtopic) {
5576
- sortSubtopic = annotatedSubtopic;
5655
+ sortSubtopic = `${sortParent} - ${annotatedSubtopic}`;
5577
5656
  }
5578
5657
  }
5579
5658
  }
@@ -5586,7 +5665,7 @@ function SubtopicAccordion({
5586
5665
  const bSort = bLabel ? getAnnotation(bLabel, "table", sortLocale) || b : b;
5587
5666
  return aSort.localeCompare(bSort, sortLocale, { sensitivity: "base" });
5588
5667
  }) : [];
5589
- return /* @__PURE__ */ React15__default.createElement(Accordion.Item, { value: `subtopic-${item}`, key: `subtopic-${item}-${index}` }, /* @__PURE__ */ React15__default.createElement(AccordionControl, null, item), /* @__PURE__ */ React15__default.createElement(Accordion.Panel, null, filtered.map((table, index2) => /* @__PURE__ */ React15__default.createElement(
5668
+ return /* @__PURE__ */ React15__default.createElement(Accordion.Item, { value: `subtopic-${item}`, key: `subtopic-${item}-${index}` }, /* @__PURE__ */ React15__default.createElement(AccordionControl, null, item.split(" - ").pop()), /* @__PURE__ */ React15__default.createElement(Accordion.Panel, null, filtered.map((table, index2) => /* @__PURE__ */ React15__default.createElement(
5590
5669
  CubeButton,
5591
5670
  {
5592
5671
  key: index2,
@@ -5595,7 +5674,7 @@ function SubtopicAccordion({
5595
5674
  locale,
5596
5675
  sortLocale,
5597
5676
  selectedItem,
5598
- parent: item
5677
+ parent: item.split(" - ").pop()
5599
5678
  }
5600
5679
  ))));
5601
5680
  })
@@ -6624,6 +6703,7 @@ function ExplorerComponent(props) {
6624
6703
  defaultMembersFilter: props.defaultMembersFilter,
6625
6704
  formatters: props.formatters,
6626
6705
  idFormatters: props.idFormatters,
6706
+ drilldownFormatters: props.drilldownFormatters,
6627
6707
  withPermalink: props.withPermalink,
6628
6708
  panels,
6629
6709
  pagination,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/data-explorer",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "main": "./dist/main.mjs",
5
5
  "types": "./dist/main.d.mts",
6
6
  "files": [