@datawheel/bespoke 0.3.13 → 0.3.15

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 (2) hide show
  1. package/dist/index.js +69 -65
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import { dataConcat, dataLoad } from 'd3plus-viz';
24
24
  import * as d3plus from 'd3plus-react';
25
25
  import Router, { useRouter } from 'next/router';
26
26
  import { useMediaQuery, useClickOutside, useDisclosure, useDebouncedValue, useSetState, useHotkeys, useFullscreen, getHotkeyHandler } from '@mantine/hooks';
27
- import { IconDice, IconBoxMultiple, IconEyeOff, IconChevronDown, IconInfoCircle, IconRefresh, IconSearch, IconPlus, IconHeading, IconApi, IconPercentage, IconChartBar, IconAlignLeft, IconSelector, IconPhoto, IconAlignCenter, IconAlignRight, IconBallpen, IconDatabase, IconMathFunction, IconUsers, IconLogout, IconTrash, IconX, IconPhotoFilled, IconFileUpload, IconUserCircle, IconEdit, IconCircleDashed, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconCircleX, IconFlag, IconFileAnalytics, IconHome, IconSettingsFilled, IconEye, IconWorldUpload, IconBraces, IconClockHour2, IconAugmentedReality, IconGitMerge, IconGripHorizontal, IconChevronLeft, IconChevronRight, IconPolaroid, IconCircleMinus, IconTable, IconCamera, IconShare, IconCirclePlus, IconLogin, IconWorld, IconLock, IconBinaryTree, IconVariable, IconArrowRightCircle, IconIndentIncrease, IconCodeDots, IconUpload, IconCodePlus, IconLink, IconSparkles, IconClipboardCheck, IconClipboardCopy, IconExternalLink, IconDownload, IconTemplate, IconCode, IconPalette, IconSettings, IconMinimize, IconMaximize, IconRss, IconGlobe, IconLinkOff } from '@tabler/icons-react';
27
+ import { IconDice, IconBoxMultiple, IconEyeOff, IconChevronDown, IconInfoCircle, IconRefresh, IconSearch, IconPlus, IconHeading, IconApi, IconPercentage, IconChartBar, IconAlignLeft, IconSelector, IconPhoto, IconAlignCenter, IconAlignRight, IconBallpen, IconDatabase, IconMathFunction, IconUsers, IconLogout, IconTrash, IconX, IconPhotoFilled, IconFileUpload, IconUserCircle, IconEdit, IconCircleDashed, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconCircleX, IconFlag, IconFileAnalytics, IconHome, IconSettingsFilled, IconEye, IconWorldUpload, IconBraces, IconClockHour2, IconAugmentedReality, IconGitMerge, IconGripHorizontal, IconChevronLeft, IconChevronRight, IconPolaroid, IconCircleMinus, IconTable, IconCamera, IconShare, IconCirclePlus, IconLogin, IconWorld, IconLock, IconBinaryTree, IconVariable, IconArrowRightCircle, IconIndentIncrease, IconCodeDots, IconUpload, IconCodePlus, IconLink, IconSparkles, IconClipboardCheck, IconClipboardCopy, IconExternalLink, IconTemplate, IconCode, IconDownload, IconPalette, IconFileTypeCsv, IconFileTypeJs, IconFileTypeXls, IconSettings, IconMinimize, IconMaximize, IconRss, IconGlobe, IconLinkOff } from '@tabler/icons-react';
28
28
  import dynamic from 'next/dynamic';
29
29
  import Link from 'next/link';
30
30
  import parse2, { Element, domToReact, Text as Text$1 } from 'html-react-parser';
@@ -7272,9 +7272,18 @@ init_varSwapRecursive();
7272
7272
  init_runConsumers();
7273
7273
  init_consts();
7274
7274
  var formatOptions = {
7275
- csv: "CSV",
7276
- json: "JSON",
7277
- xlsx: "XLSX"
7275
+ csv: {
7276
+ extension: "CSV",
7277
+ icon: IconFileTypeCsv
7278
+ },
7279
+ json: {
7280
+ extension: "JSON",
7281
+ icon: IconFileTypeJs
7282
+ },
7283
+ xlsx: {
7284
+ extension: "XLSX",
7285
+ icon: IconFileTypeXls
7286
+ }
7278
7287
  };
7279
7288
  var DEFAULT_TRANSLATIONS2 = {
7280
7289
  "data_source": "Data Source",
@@ -7293,7 +7302,7 @@ var DEFAULT_TRANSLATIONS2 = {
7293
7302
  "rows_preview": "(First {nrows} rows as preview)",
7294
7303
  "choose_format": "Choose format",
7295
7304
  "processing_file": "Processing file...",
7296
- "download": "Download full selected dataset in {fmt} format",
7305
+ "download": "Download data as",
7297
7306
  "preview": "Preview",
7298
7307
  "copy": "Click to copy",
7299
7308
  "copied": "Copied!"
@@ -7330,9 +7339,9 @@ function DataTab(props) {
7330
7339
  const [selectedSource, setSelectedSource] = useState();
7331
7340
  const [selectedDataset, setSelectedDataset] = useState();
7332
7341
  const [fileProcessing, setFileProcessing] = useState(false);
7333
- const [fileFormat, setFileFormat] = useState(formatOptions.csv);
7334
7342
  const [previewsSource, setPreviewsSource] = useState({});
7335
- const [loadingPreview, setLoadingPreview] = useState(false);
7343
+ const [loadingPreview, setLoadingPreview] = useState(true);
7344
+ const [loadingSources, setLoadingSources] = useState(true);
7336
7345
  const { sectionVariables, setSectionVariables, resetSectionVariables } = useSectionVariables(section.id);
7337
7346
  const blockIds = section.blocks || [];
7338
7347
  const state = useAppSelector((state2) => state2);
@@ -7461,6 +7470,7 @@ function DataTab(props) {
7461
7470
  }
7462
7471
  }
7463
7472
  }
7473
+ setLoadingSources(false);
7464
7474
  }
7465
7475
  }, [blocksData]);
7466
7476
  useEffect(() => {
@@ -7502,28 +7512,28 @@ function DataTab(props) {
7502
7512
  }
7503
7513
  }
7504
7514
  }, [selectedDataset, selectedSource]);
7505
- const getFileName = (nameformat, fileFormat2) => {
7506
- const finalNameFormat = nameformat === fileFormat2 ? "" : `-${nameformat}`.toLowerCase();
7515
+ const getFileName = (nameformat, fileFormat) => {
7516
+ const finalNameFormat = nameformat === fileFormat ? "" : `-${nameformat}`.toLowerCase();
7507
7517
  if (selectedSource) {
7508
7518
  const fileIndex = selectedSource.data.length > 1 && selectedDataset ? `-${parseInt(selectedDataset, 10) + 1}` : "";
7509
- return `${slugify_default(selectedSource.fileName)}${finalNameFormat}${fileIndex}.${fileFormat2.toLowerCase()}`;
7519
+ return `${slugify_default(selectedSource.fileName)}${finalNameFormat}${fileIndex}.${fileFormat.toLowerCase()}`;
7510
7520
  }
7511
- return `${finalNameFormat}.${fileFormat2}`;
7521
+ return `${finalNameFormat}.${fileFormat}`;
7512
7522
  };
7513
- const onSaveClick = async () => {
7523
+ const onSaveClick = async (fileFormat) => {
7514
7524
  if (selectedSource) {
7515
7525
  setFileProcessing(true);
7516
7526
  const zipFile = new JSZip();
7517
7527
  const filename = getFileName(fileFormat, fileFormat);
7518
7528
  try {
7519
7529
  switch (fileFormat) {
7520
- case formatOptions.json:
7530
+ case formatOptions.json.extension:
7521
7531
  zipFile.file(filename, JSON.stringify(currentPreview));
7522
7532
  break;
7523
- case formatOptions.csv:
7533
+ case formatOptions.csv.extension:
7524
7534
  zipFile.file(filename, csvFormat(currentPreview));
7525
7535
  break;
7526
- case formatOptions.xlsx:
7536
+ case formatOptions.xlsx.extension:
7527
7537
  const { utils, write } = await import('xlsx');
7528
7538
  const wb = utils.book_new();
7529
7539
  utils.book_append_sheet(
@@ -7570,8 +7580,9 @@ function DataTab(props) {
7570
7580
  )), [sourcesOptions, selectedSource, sourcesToLoad]);
7571
7581
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-data", children: [
7572
7582
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
7573
- sourcesOptions.length === 0 && /* @__PURE__ */ jsx("p", { children: "No data sources defined." }),
7574
- sourcesOptions.length > 1 && /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_data_src"]}:`, children: /* @__PURE__ */ jsx(Group, { spacing: "xs", children: sourcesButtons }) }),
7583
+ /* @__PURE__ */ jsx(LoadingOverlay, { visible: loadingSources, overlayBlur: 2 }),
7584
+ sourcesOptions.length === 0 && !loadingSources && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: "1rem" }), title: "Oops!", children: translations["no_data_src"] }),
7585
+ sourcesOptions.length > 1 && sourcesOptions.length === sourcesToLoad.length && !loadingSources && /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_data_src"]}:`, children: /* @__PURE__ */ jsx(Group, { spacing: "xs", children: sourcesButtons }) }),
7575
7586
  selectedSource && selectedDataset && /* @__PURE__ */ jsx(Stack, { spacing: "xs", children: /* @__PURE__ */ jsx(
7576
7587
  Input.Wrapper,
7577
7588
  {
@@ -7596,7 +7607,7 @@ function DataTab(props) {
7596
7607
  /* @__PURE__ */ jsx(
7597
7608
  CopyButton,
7598
7609
  {
7599
- value: selectedSource.data[selectedDataset] === "string" ? selectedSource.data[selectedDataset] : "",
7610
+ value: typeof selectedSource.data[selectedDataset] === "string" ? selectedSource.data[selectedDataset] : "",
7600
7611
  timeout: 2e3,
7601
7612
  children: ({ copied, copy }) => /* @__PURE__ */ jsx(Tooltip, { label: copied ? translations["copied"] : translations["copy"], withArrow: true, position: "top", children: /* @__PURE__ */ jsx(
7602
7613
  ActionIcon,
@@ -7621,32 +7632,21 @@ function DataTab(props) {
7621
7632
  children: translations["open_in_window"].replace("{src}", selectedSource.title)
7622
7633
  }
7623
7634
  ) }),
7624
- /* @__PURE__ */ jsxs(Stack, { pos: "relative", mih: "450px", children: [
7625
- /* @__PURE__ */ jsx(LoadingOverlay, { visible: loadingPreview }),
7635
+ /* @__PURE__ */ jsxs(Stack, { pos: "relative", mih: "430px", children: [
7636
+ /* @__PURE__ */ jsx(LoadingOverlay, { visible: loadingPreview && sourcesOptions.length > 0, overlayBlur: 2 }),
7626
7637
  selectedSource && !loadingPreview && currentPreview.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
7627
- /* @__PURE__ */ jsx(Box, { h: "300px", children: /* @__PURE__ */ jsx(SortableTable, { data: currentPreview.slice(0, PREVIEW_SIZE) }) }),
7628
- /* @__PURE__ */ jsx(Space, { h: "xs" }),
7629
- /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_format"]}: ${getFileName(fileFormat, fileFormat)}`, children: /* @__PURE__ */ jsx(Button.Group, { children: Object.keys(formatOptions).map((format2) => /* @__PURE__ */ jsx(
7630
- Button,
7631
- {
7632
- leftIcon: /* @__PURE__ */ jsx(IconTable, { size: 16 }),
7633
- onClick: () => setFileFormat(formatOptions[format2]),
7634
- variant: fileFormat === formatOptions[format2] ? "filled" : "default",
7635
- fullWidth: true,
7636
- children: formatOptions[format2]
7637
- },
7638
- `format-${format2}`
7639
- )) }) }),
7640
- /* @__PURE__ */ jsx(
7638
+ /* @__PURE__ */ jsx(Box, { h: "350px", children: /* @__PURE__ */ jsx(SortableTable, { data: currentPreview.slice(0, PREVIEW_SIZE) }) }),
7639
+ /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["download"]}:`, children: /* @__PURE__ */ jsx(Button.Group, { children: Object.values(formatOptions).map((format2) => /* @__PURE__ */ jsx(
7641
7640
  Button,
7642
7641
  {
7643
- leftIcon: /* @__PURE__ */ jsx(IconDownload, { size: 16 }),
7642
+ leftIcon: /* @__PURE__ */ jsx(format2.icon, { size: 24 }),
7643
+ onClick: () => onSaveClick(format2.extension),
7644
7644
  loading: fileProcessing,
7645
- onClick: onSaveClick,
7646
7645
  fullWidth: true,
7647
- children: /* @__PURE__ */ jsx("span", { children: fileProcessing ? translations["processing_file"] : translations["download"].replace("{fmt}", fileFormat) })
7648
- }
7649
- )
7646
+ children: format2.extension
7647
+ },
7648
+ `format-${format2.extension}`
7649
+ )) }) })
7650
7650
  ] })
7651
7651
  ] })
7652
7652
  ] });
@@ -7677,7 +7677,7 @@ var DEFAULT_TRANSLATIONS3 = {
7677
7677
  function ImageTab(props) {
7678
7678
  const { section } = props;
7679
7679
  const blocksIds = section.blocks || [];
7680
- const vizBlocks = useAppSelector((state) => blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => block.type === "visualization"));
7680
+ const vizBlocks = useAppSelector((state) => blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => block.type === "visualization" && state.variables.status[block.id].allowed));
7681
7681
  const [imageContext, setImageContext] = useState(contextOptions.section);
7682
7682
  const [imageFormat, setImageFormat] = useState(formatOptions2.png);
7683
7683
  const [imageProcessing, setImageProcessing] = useState(false);
@@ -7805,31 +7805,35 @@ function ImageTab(props) {
7805
7805
  }, [vizSelected]);
7806
7806
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-image", children: [
7807
7807
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
7808
- /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_area"]}:`, children: /* @__PURE__ */ jsxs(Button.Group, { children: [
7809
- /* @__PURE__ */ jsx(
7810
- Button,
7811
- {
7812
- leftIcon: /* @__PURE__ */ jsx(IconTemplate, { size: 16 }),
7813
- onClick: () => {
7814
- setImageContext(contextOptions.section);
7815
- setImageFormat(formatOptions2.png);
7808
+ /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_area"]}:`, children: /* @__PURE__ */ jsx(
7809
+ SegmentedControl,
7810
+ {
7811
+ fullWidth: true,
7812
+ value: imageContext,
7813
+ data: [
7814
+ {
7815
+ value: contextOptions.section,
7816
+ label: /* @__PURE__ */ jsxs(Center, { children: [
7817
+ /* @__PURE__ */ jsx(IconTemplate, { size: "1rem" }),
7818
+ /* @__PURE__ */ jsx(Box, { ml: 10, children: translations["entire_section"] })
7819
+ ] })
7816
7820
  },
7817
- variant: imageContext === contextOptions.section ? "filled" : "default",
7818
- fullWidth: true,
7819
- children: translations["entire_section"]
7820
- }
7821
- ),
7822
- vizAvailable.length > 0 && /* @__PURE__ */ jsx(
7823
- Button,
7824
- {
7825
- leftIcon: /* @__PURE__ */ jsx(IconChartBar, { size: 16 }),
7826
- onClick: () => setImageContext(contextOptions.viz),
7827
- variant: imageContext === contextOptions.viz ? "filled" : "default",
7828
- fullWidth: true,
7829
- children: translations["viz_only"]
7821
+ {
7822
+ value: contextOptions.viz,
7823
+ label: /* @__PURE__ */ jsxs(Center, { children: [
7824
+ /* @__PURE__ */ jsx(IconChartBar, { size: "1rem" }),
7825
+ /* @__PURE__ */ jsx(Box, { ml: 10, children: translations["viz_only"] })
7826
+ ] })
7827
+ }
7828
+ ],
7829
+ onChange: (newValue) => {
7830
+ setImageContext(newValue);
7831
+ if (newValue === contextOptions.section) {
7832
+ setImageFormat(formatOptions2.png);
7833
+ }
7830
7834
  }
7831
- )
7832
- ] }) }),
7835
+ }
7836
+ ) }),
7833
7837
  imageContext === contextOptions.viz && vizAvailable.length > 0 && /* @__PURE__ */ jsxs(
7834
7838
  Input.Wrapper,
7835
7839
  {
@@ -8530,8 +8534,8 @@ init_esm_shims();
8530
8534
  init_store2();
8531
8535
  var ALLOWED_UNITS = ["px", "%"];
8532
8536
  var formatters = {
8533
- px: (value) => !Number.isNaN(parseFloat(value)) ? `${value}px`.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",") : "px",
8534
- ["%"]: (value) => !Number.isNaN(parseFloat(value)) ? `${value}%`.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",") : "%"
8537
+ px: (value) => !Number.isNaN(parseFloat(value)) ? `${value}px`.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,") : "px",
8538
+ "%": (value) => !Number.isNaN(parseFloat(value)) ? `${value}%`.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,") : "%"
8535
8539
  };
8536
8540
  var WidthInputProps = {
8537
8541
  "px": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/bespoke",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "Content management system for creating automated data reports",
5
5
  "exports": {
6
6
  ".": {