@datawheel/bespoke 0.2.4 → 0.2.5

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/index.css CHANGED
@@ -7,7 +7,7 @@
7
7
  color: red;
8
8
  }
9
9
 
10
- /* cms/components/components/ConsoleVariable.css */
10
+ /* components/builder/components/ConsoleVariable.css */
11
11
  .mantine-Prism-root.cr-variable {
12
12
  font-size: 11px;
13
13
  padding: 0;
@@ -29,11 +29,11 @@
29
29
  margin-right: 4px;
30
30
  }
31
31
 
32
- /* cms/components/reportVizes/Graphic.css */
32
+ /* components/blocks/types/renderers/viz-types/Graphic.css */
33
33
 
34
34
  /* css/mixins.css */
35
35
 
36
- /* cms/components/reportVizes/Table.css */
36
+ /* components/blocks/types/renderers/viz-types/Table.css */
37
37
  .cms-table-viz-container .cms-viz-figure,
38
38
  .cp-table-viz-container .cp-viz-figure {
39
39
  height: auto !important;
@@ -278,12 +278,12 @@
278
278
  text-decoration: underline;
279
279
  }
280
280
 
281
- /* cms/editors/MonacoWrapper.css */
281
+ /* components/builder/editors/MonacoWrapper.css */
282
282
  .cr-monaco-container {
283
283
  height: 100%;
284
284
  }
285
285
 
286
- /* cms/editors/MCEWrapper.css */
286
+ /* components/builder/editors/MCEWrapper.css */
287
287
  .tox-notifications-container {
288
288
  display: none;
289
289
  }
package/dist/index.js CHANGED
@@ -13,14 +13,14 @@ import { schema, normalize } from 'normalizr';
13
13
  import { createSlice, configureStore } from '@reduxjs/toolkit';
14
14
  import { HYDRATE, createWrapper } from 'next-redux-wrapper';
15
15
  import { Notifications, notifications } from '@mantine/notifications';
16
- import React, { forwardRef, useMemo, useState, useCallback, useContext, useEffect, createContext, memo, useRef, Fragment as Fragment$1, createElement } from 'react';
16
+ import React, { forwardRef, createContext, useMemo, useState, useCallback, useContext, useEffect, memo, useRef, Fragment as Fragment$1, createElement } from 'react';
17
17
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
18
18
  import { useDispatch, useSelector } from 'react-redux';
19
- import { Stack, Text, Badge, Group, useMantineTheme, Flex, packSx, Tooltip, ActionIcon, Modal, Button, SegmentedControl, Select, MultiSelect, Center, Grid, Title, Radio, NumberInput, TextInput, Switch, Box, List, Menu, Anchor, MantineProvider, Divider, Burger, Navbar, ScrollArea, Avatar, AppShell, UnstyledButton, ThemeIcon, LoadingOverlay, Skeleton, Image, Card, Container, Loader, Alert, Collapse, Space, Code, Textarea, rem, Paper, Input, Popover, Checkbox, Drawer, Overlay, SimpleGrid, Autocomplete, Tabs, Header, px, FileInput, Accordion, HoverCard, CopyButton, Col } from '@mantine/core';
19
+ import { Stack, Text, Badge, Group, useMantineTheme, Flex, packSx, Tooltip, ActionIcon, Modal, Button, SegmentedControl, Select, MultiSelect, Center, Grid, Title, Radio, NumberInput, TextInput, Switch, Box, List, Menu, Anchor, MantineProvider, Divider, Burger, Navbar, ScrollArea, Avatar, AppShell, UnstyledButton, ThemeIcon, LoadingOverlay, Skeleton, Image, Card, Container, Loader, Alert, Collapse, Space, Code, Textarea, rem, Paper, Autocomplete, Input, Popover, Checkbox, Drawer, Overlay, SimpleGrid, Tabs, Header, px, FileInput, Accordion, HoverCard, CopyButton, Col } from '@mantine/core';
20
20
  import { dataConcat } from 'd3plus-viz';
21
21
  import * as d3plus from 'd3plus-react';
22
22
  import Router, { useRouter } from 'next/router';
23
- import { IconInfoCircle, IconRefresh, IconSearch, IconAlignLeft, IconAlignCenter, IconAlignRight, IconBoxMargin, IconTable, IconMathFunction, IconUsers, IconLogout, IconTrash, IconUserCircle, IconEdit, IconDatabase, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconAlarmFilled, IconBox, IconLink, IconCircleX, IconFlag, IconCirclePlus, IconFileAnalytics, IconPlus, IconHome, IconX, IconChevronDown, IconCamera, IconShare, IconCircleDashed, IconListSearch, IconExternalLink, IconSettings, IconFileOff, IconFilesOff, IconHierarchy3, IconMenu, IconApi, IconPolaroid, IconCircleMinus, IconEyeOff, IconPhoto, IconChevronLeft, IconChevronRight, IconLogin, IconWorld, IconLock, IconVariable, IconArrowRightCircle, IconDownload, IconTemplate, IconChartBar, IconCode, IconUpload, IconCodePlus, IconClipboardCheck, IconClipboardCopy, IconPalette, IconEye, IconMinimize, IconMaximize, IconRss, IconGlobe, IconLinkOff } from '@tabler/icons-react';
23
+ import { IconInfoCircle, IconRefresh, IconSearch, IconAlignLeft, IconAlignCenter, IconAlignRight, IconBoxMargin, IconTable, IconMathFunction, IconUsers, IconLogout, IconTrash, IconX, IconUserCircle, IconEdit, IconDatabase, IconServer, IconPencil, IconAlertCircle, IconCircleCheck, IconPlayerPlay, IconAlarmFilled, IconBox, IconLink, IconCircleX, IconFlag, IconCirclePlus, IconFileAnalytics, IconPlus, IconHome, IconChevronDown, IconCamera, IconShare, IconCircleDashed, IconListSearch, IconExternalLink, IconSettings, IconFileOff, IconFilesOff, IconHierarchy3, IconMenu, IconApi, IconPolaroid, IconCircleMinus, IconEyeOff, IconPhoto, IconChevronLeft, IconChevronRight, IconLogin, IconWorld, IconLock, IconVariable, IconArrowRightCircle, IconDownload, IconTemplate, IconChartBar, IconCode, IconUpload, IconCodePlus, IconClipboardCheck, IconClipboardCopy, IconPalette, IconEye, IconMinimize, IconMaximize, IconRss, IconGlobe, IconLinkOff } from '@tabler/icons-react';
24
24
  import { useMediaQuery, useDisclosure, useDebouncedValue, useHotkeys, useFullscreen, getHotkeyHandler } from '@mantine/hooks';
25
25
  import dynamic from 'next/dynamic';
26
26
  import Link from 'next/link';
@@ -91,11 +91,13 @@ function httpPOST(axios6, request, transformPayload) {
91
91
  }
92
92
  function httpDELETE(axios6, request, transformPayload) {
93
93
  const config = typeof request === "string" ? { url: request } : request;
94
- return (payload) => http(axios6, {
95
- ...config,
96
- method: "DELETE",
97
- data: transformPayload ? transformPayload(payload) : payload
98
- });
94
+ return (payload) => {
95
+ return http(axios6, {
96
+ ...config,
97
+ method: "DELETE",
98
+ params: transformPayload ? transformPayload(payload) : payload
99
+ });
100
+ };
99
101
  }
100
102
  var init_lib = __esm({
101
103
  "api/http/lib.ts"() {
@@ -3172,9 +3174,9 @@ var init_Stat = __esm({
3172
3174
  }
3173
3175
  });
3174
3176
 
3175
- // cms/components/reportVizes/Graphic.css
3177
+ // components/blocks/types/renderers/viz-types/Graphic.css
3176
3178
  var init_ = __esm({
3177
- "cms/components/reportVizes/Graphic.css"() {
3179
+ "components/blocks/types/renderers/viz-types/Graphic.css"() {
3178
3180
  }
3179
3181
  });
3180
3182
  function Graphic({ config, dataFormat }) {
@@ -3223,7 +3225,7 @@ function Graphic({ config, dataFormat }) {
3223
3225
  ] });
3224
3226
  }
3225
3227
  var init_Graphic = __esm({
3226
- "cms/components/reportVizes/Graphic.tsx"() {
3228
+ "components/blocks/types/renderers/viz-types/Graphic.tsx"() {
3227
3229
  init_esm_shims();
3228
3230
  init_Stat();
3229
3231
  init_();
@@ -3235,14 +3237,14 @@ function HTML({ config }) {
3235
3237
  return /* @__PURE__ */ jsx("div", { className: "cp-viz cp-html", dangerouslySetInnerHTML: { __html: config.html } });
3236
3238
  }
3237
3239
  var init_HTML = __esm({
3238
- "cms/components/reportVizes/HTML.tsx"() {
3240
+ "components/blocks/types/renderers/viz-types/HTML.tsx"() {
3239
3241
  init_esm_shims();
3240
3242
  }
3241
3243
  });
3242
3244
 
3243
- // cms/components/reportVizes/Table.css
3245
+ // components/blocks/types/renderers/viz-types/Table.css
3244
3246
  var init_2 = __esm({
3245
- "cms/components/reportVizes/Table.css"() {
3247
+ "components/blocks/types/renderers/viz-types/Table.css"() {
3246
3248
  }
3247
3249
  });
3248
3250
  function Table({ config, dataFormat }) {
@@ -3267,7 +3269,7 @@ function Table({ config, dataFormat }) {
3267
3269
  }
3268
3270
  var Table_default;
3269
3271
  var init_Table = __esm({
3270
- "cms/components/reportVizes/Table.jsx"() {
3272
+ "components/blocks/types/renderers/viz-types/Table.jsx"() {
3271
3273
  init_esm_shims();
3272
3274
  init_2();
3273
3275
  Table_default = Table;
@@ -3487,12 +3489,12 @@ init_esm_shims();
3487
3489
 
3488
3490
  // frontend/components/explore/ExploreFilters.tsx
3489
3491
  init_esm_shims();
3490
- function ExploreFilters({ metadata, onFilter, initialReportId, initialVariantId }) {
3492
+ function ExploreFilters({ metadata, onFilter, initialReportId, initialVariantId, translations }) {
3491
3493
  const [selectors, setSelectors] = useState([]);
3492
3494
  const [filters, setFilters] = useState({ profile: void 0, variant: void 0 });
3493
3495
  const [selectedProfile, setSelectedProfile] = useState();
3494
3496
  const [selectedVariant, setSelectedVariant] = useState();
3495
- const allMember = { id: void 0, name: "All" };
3497
+ const allMember = { id: void 0, name: translations["filters_all"] };
3496
3498
  const getVariantsCombinatory = (variantsArrays) => {
3497
3499
  const combinatory = variantsArrays.reduce((a, b) => a.reduce((r, v) => r.concat(b.map((w) => [].concat(v, w))), [])).map((combination) => {
3498
3500
  if (!Array.isArray(combination))
@@ -3554,7 +3556,7 @@ function ExploreFilters({ metadata, onFilter, initialReportId, initialVariantId
3554
3556
  {
3555
3557
  variant: s.id === selectedProfile?.id ? "outline" : "subtle",
3556
3558
  onClick: () => onClickProfile(s),
3557
- children: s.name
3559
+ children: translations?.dimension[s.name] ?? s.name
3558
3560
  },
3559
3561
  `p-${s.id}`
3560
3562
  )) }),
@@ -3564,7 +3566,7 @@ function ExploreFilters({ metadata, onFilter, initialReportId, initialVariantId
3564
3566
  {
3565
3567
  variant: v.id === selectedVariant?.id ? "outline" : "subtle",
3566
3568
  onClick: () => onClickVariant(v),
3567
- children: v.name
3569
+ children: translations?.dimension[v.name] ?? v.name
3568
3570
  },
3569
3571
  `v-${v.id}`
3570
3572
  )) }),
@@ -3677,11 +3679,21 @@ var ExploreResults_default = ExploreResults;
3677
3679
 
3678
3680
  // frontend/components/explore/Explore.tsx
3679
3681
  init_store2();
3682
+ var DEFAULT_TRANSLATIONS = {
3683
+ "try_another": "Try another search or filter.",
3684
+ "search": "Search",
3685
+ "filters_all": "All",
3686
+ "no_results": "No Results",
3687
+ report: {},
3688
+ dimension: {},
3689
+ variant: {}
3690
+ };
3680
3691
  function BespokeExplore({
3681
3692
  locale,
3682
3693
  profilePrefix,
3683
3694
  initialReportId,
3684
3695
  initialVariantId,
3696
+ translations = DEFAULT_TRANSLATIONS,
3685
3697
  onSelect,
3686
3698
  reportTile
3687
3699
  }) {
@@ -3746,11 +3758,12 @@ function BespokeExplore({
3746
3758
  const onClearInput = () => {
3747
3759
  setQuery("");
3748
3760
  };
3761
+ const exploreTranslations = { ...DEFAULT_TRANSLATIONS, ...translations };
3749
3762
  return /* @__PURE__ */ jsxs(Container, { fluid: true, pt: "1em", children: [
3750
3763
  /* @__PURE__ */ jsx(
3751
3764
  TextInput,
3752
3765
  {
3753
- placeholder: "Search",
3766
+ placeholder: exploreTranslations["search"],
3754
3767
  size: "xl",
3755
3768
  onChange: (e) => setQuery(e.target.value),
3756
3769
  readOnly: loading,
@@ -3776,11 +3789,12 @@ function BespokeExplore({
3776
3789
  metadata,
3777
3790
  onFilter: onFilterChange,
3778
3791
  initialReportId,
3779
- initialVariantId
3792
+ initialVariantId,
3793
+ translations: exploreTranslations
3780
3794
  }
3781
3795
  ),
3782
3796
  /* @__PURE__ */ jsx(LoadingOverlay, { visible: loading }),
3783
- !loading && results.length === 0 && /* @__PURE__ */ jsx(Alert, { title: "No results", color: "blue", children: "Try another search or filter." }),
3797
+ !loading && results.length === 0 && /* @__PURE__ */ jsx(Alert, { title: exploreTranslations["no_results"], color: "blue", children: exploreTranslations["try_another"] }),
3784
3798
  !loading && /* @__PURE__ */ jsx(ExploreResults_default, { results, profilePrefix, onSelect, reportTile })
3785
3799
  ] });
3786
3800
  }
@@ -3795,6 +3809,7 @@ function BespokeExploreModal({
3795
3809
  icon = /* @__PURE__ */ jsx(IconSearch, { size: 20 }),
3796
3810
  actionIconProps = {},
3797
3811
  modalProps = {},
3812
+ tooltipProps = {},
3798
3813
  children
3799
3814
  }) {
3800
3815
  const [opened, setOpened] = useState(false);
@@ -3813,7 +3828,7 @@ function BespokeExploreModal({
3813
3828
  const actionIcon = /* @__PURE__ */ jsx(ActionIcon, { ...btnConfig, onClick: () => setOpened(true), children: icon });
3814
3829
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3815
3830
  /* @__PURE__ */ jsx(Modal, { ...modalProps, ...mdlConfig, children: /* @__PURE__ */ jsx(Explore_default, { ...exploreProps, onSelect: () => setOpened(false) }) }),
3816
- /* @__PURE__ */ jsx("div", { onClick: () => setOpened(true), children: children ? /* @__PURE__ */ jsx(Tooltip, { label: "Click to search", children: /* @__PURE__ */ jsxs(
3831
+ /* @__PURE__ */ jsx("div", { onClick: () => setOpened(true), children: children ? /* @__PURE__ */ jsx(Tooltip, { label: "Click to search", ...tooltipProps, children: /* @__PURE__ */ jsxs(
3817
3832
  Group,
3818
3833
  {
3819
3834
  spacing: "sm",
@@ -3859,7 +3874,13 @@ var useCustomItem = (reportItem) => {
3859
3874
  }
3860
3875
  return Tile;
3861
3876
  };
3862
- function BespokeSearch({ locale, profilePrefix, autocompleteProps = {}, children }) {
3877
+ function BespokeSearch({
3878
+ locale,
3879
+ profilePrefix,
3880
+ autocompleteProps = {},
3881
+ tooltipProps = {},
3882
+ children
3883
+ }) {
3863
3884
  const dispatch = useAppDispatch();
3864
3885
  const currentLocale = useAppSelector((state) => state.status.currentLocale);
3865
3886
  const localeDefault9 = useAppSelector((state) => state.status.localeDefault);
@@ -3975,7 +3996,7 @@ function BespokeSearch({ locale, profilePrefix, autocompleteProps = {}, children
3975
3996
  ...acConfig
3976
3997
  }
3977
3998
  );
3978
- const finalElement = children ? /* @__PURE__ */ jsx(Tooltip, { label: "Click to search", disabled: visible, children: /* @__PURE__ */ jsxs(
3999
+ const finalElement = children ? /* @__PURE__ */ jsx(Tooltip, { label: "Click to search", disabled: visible, ...tooltipProps, children: /* @__PURE__ */ jsxs(
3979
4000
  Group,
3980
4001
  {
3981
4002
  spacing: "sm",
@@ -4094,6 +4115,20 @@ function SubtitleView({ subtitle, tooltip }) {
4094
4115
  init_esm_shims();
4095
4116
  init_sanitizeBlockContent();
4096
4117
  init_hooks();
4118
+
4119
+ // frontend/components/report/context/TranslationsProvider.tsx
4120
+ init_esm_shims();
4121
+ var TranslationsContext = createContext({});
4122
+ function useBespokeTranslations(key) {
4123
+ const translations = useContext(TranslationsContext);
4124
+ if (key) {
4125
+ return translations[key] ?? translations;
4126
+ }
4127
+ return translations;
4128
+ }
4129
+ function TranslationsProvider({ translations, children }) {
4130
+ return /* @__PURE__ */ jsx(TranslationsContext.Provider, { value: translations || {}, children });
4131
+ }
4097
4132
  function TitleView({ title, tooltip, slug, settings }) {
4098
4133
  const titleHTML = sanitizeBlockContent_default(title) || "<span class='cr-block-placeholder'>Title</span>";
4099
4134
  const tooltipHTML = sanitizeBlockContent_default(tooltip);
@@ -4116,12 +4151,14 @@ function TitleView({ title, tooltip, slug, settings }) {
4116
4151
  }
4117
4152
  );
4118
4153
  const locale = currentLocale;
4154
+ const translations = useBespokeTranslations();
4119
4155
  const finalElement = useMemo(() => {
4120
4156
  let component = /* @__PURE__ */ jsx(Fragment, {});
4121
4157
  if (searchOnClick === "modal") {
4122
4158
  component = /* @__PURE__ */ jsx(ExploreModal_default, { exploreProps: {
4123
4159
  locale,
4124
4160
  profilePrefix,
4161
+ translations: translations["explore"],
4125
4162
  initialReportId: initialIds.reportId,
4126
4163
  initialVariantId: initialIds.variantId
4127
4164
  }, children: titleElement });
@@ -5360,10 +5397,10 @@ function SelectorPreview(config) {
5360
5397
  // components/blocks/types/renderers/Generator.tsx
5361
5398
  init_esm_shims();
5362
5399
 
5363
- // cms/components/components/InputMenuItem.tsx
5400
+ // components/builder/components/InputMenuItem.tsx
5364
5401
  init_esm_shims();
5365
5402
 
5366
- // cms/components/components/ConsoleVariable.tsx
5403
+ // components/builder/components/ConsoleVariable.tsx
5367
5404
  init_esm_shims();
5368
5405
  var evalType = (value) => {
5369
5406
  let t = typeof value;
@@ -5519,7 +5556,7 @@ function ConsoleVariable({
5519
5556
  }
5520
5557
  var ConsoleVariable_default = ConsoleVariable;
5521
5558
 
5522
- // cms/components/components/InputMenuItem.tsx
5559
+ // components/builder/components/InputMenuItem.tsx
5523
5560
  init_store2();
5524
5561
  function InputMenuItem({
5525
5562
  reserved = [],
@@ -6146,6 +6183,23 @@ var formatOptions = {
6146
6183
  json: "JSON",
6147
6184
  xlsx: "XLSX"
6148
6185
  };
6186
+ var DEFAULT_TRANSLATIONS2 = {
6187
+ "data_source": "Data Source",
6188
+ "no_data_src": "No data sources defined",
6189
+ "viz_source": "Visualization Source",
6190
+ "error_generating": "Error generating file.",
6191
+ "choose_data_src": "Choose data source",
6192
+ "original_src": "Original {src}",
6193
+ "loading": "Loading...",
6194
+ "error_preview": `Sorry. We couldn&apos;t generate the data preview as a table.
6195
+ Try to open the source and check the data directly.`,
6196
+ "open_in_window": "Open {src} response in a new window",
6197
+ "formatted_src": "Formatted {src}",
6198
+ "rows_preview": "(First {nrows} rows as preview)",
6199
+ "choose_format": "Choose format",
6200
+ "processing_file": "Processing file...",
6201
+ "download": "Download full dataset in {fmt} format"
6202
+ };
6149
6203
  function DataTab(props) {
6150
6204
  const { section } = props;
6151
6205
  const readMemberFn = useReadMemberFn();
@@ -6168,7 +6222,7 @@ function DataTab(props) {
6168
6222
  {
6169
6223
  ix,
6170
6224
  id: block.id,
6171
- title: `Data Source ${ix + 1}`,
6225
+ title: `${translations["data_source"]} ${ix + 1}`,
6172
6226
  path: apiUrl
6173
6227
  }
6174
6228
  );
@@ -6196,7 +6250,7 @@ function DataTab(props) {
6196
6250
  {
6197
6251
  ix,
6198
6252
  id: block.id,
6199
- title: `Viz Data Source ${ix + 1}`,
6253
+ title: `${translations["viz_source"]} ${ix + 1}`,
6200
6254
  path: d3Props.config._api
6201
6255
  }
6202
6256
  );
@@ -6206,7 +6260,7 @@ function DataTab(props) {
6206
6260
  {
6207
6261
  ix,
6208
6262
  id: block.id,
6209
- title: `Viz Data Source ${ix + 1}`,
6263
+ title: `${translations["viz_source"]} ${ix + 1}`,
6210
6264
  path: d3Props.config.data
6211
6265
  }
6212
6266
  );
@@ -6218,7 +6272,7 @@ function DataTab(props) {
6218
6272
  {
6219
6273
  ix,
6220
6274
  id: block.id,
6221
- title: `Viz Data Source ${ix + 1}`,
6275
+ title: `${translations["viz_source"]} ${ix + 1}`,
6222
6276
  path: dataItem
6223
6277
  }
6224
6278
  );
@@ -6234,6 +6288,8 @@ function DataTab(props) {
6234
6288
  const [fileFormat, setFileFormat] = useState(formatOptions.csv);
6235
6289
  const [previewsSource, setPreviewsSource] = useState({});
6236
6290
  const [loadingPreview, setLoadingPreview] = useState(false);
6291
+ const optionsTranslations = useBespokeTranslations("options");
6292
+ const translations = { ...DEFAULT_TRANSLATIONS2, ...optionsTranslations["data_tab"] };
6237
6293
  useEffect(() => {
6238
6294
  if (sourcesOptions[0]) {
6239
6295
  setSelectedSource(sourcesOptions[0]);
@@ -6313,7 +6369,7 @@ function DataTab(props) {
6313
6369
  saveAs(content, getFileName(fileFormat, "zip"));
6314
6370
  });
6315
6371
  } catch (error) {
6316
- console.error("Error generating file", error);
6372
+ console.error(translations["error_generating"], error);
6317
6373
  setFileProcessing(false);
6318
6374
  }
6319
6375
  }
@@ -6322,7 +6378,7 @@ function DataTab(props) {
6322
6378
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-data", children: [
6323
6379
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
6324
6380
  sourcesOptions.length === 0 && /* @__PURE__ */ jsx("p", { children: "No data sources defined." }),
6325
- sourcesOptions.length > 1 && /* @__PURE__ */ jsx(Input.Wrapper, { label: "Choose Data Source:", children: /* @__PURE__ */ jsx(Group, { spacing: "xs", children: sourcesOptions.map((source, ix) => /* @__PURE__ */ jsx(
6381
+ sourcesOptions.length > 1 && /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_data_src"]}:`, children: /* @__PURE__ */ jsx(Group, { spacing: "xs", children: sourcesOptions.map((source, ix) => /* @__PURE__ */ jsx(
6326
6382
  Button,
6327
6383
  {
6328
6384
  leftIcon: /* @__PURE__ */ jsx(IconDatabase, { size: 16 }),
@@ -6332,15 +6388,21 @@ function DataTab(props) {
6332
6388
  },
6333
6389
  `source-${source.id}-${ix}`
6334
6390
  )) }) }),
6335
- selectedSource && /* @__PURE__ */ jsx(CopyInput, { title: `Original ${selectedSource.title}:`, url: selectedSource.path }),
6336
- selectedSource && loadingPreview && /* @__PURE__ */ jsx(Fragment, { children: "Loading..." }),
6337
- selectedSource && !loadingPreview && currentPreview.length === 0 && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: "1rem" }), title: "Oops!", children: "Sorry. We couldn't generate the data preview as a table. Try to open the source and check the data directly." }),
6391
+ selectedSource && /* @__PURE__ */ jsx(
6392
+ CopyInput,
6393
+ {
6394
+ title: `${translations["original_src"].replace("{src}", selectedSource.title)}:`,
6395
+ url: selectedSource.path
6396
+ }
6397
+ ),
6398
+ selectedSource && loadingPreview && /* @__PURE__ */ jsx(Fragment, { children: translations["loading"] }),
6399
+ selectedSource && !loadingPreview && currentPreview.length === 0 && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: "1rem" }), title: "Oops!", children: translations["error_preview"] }),
6338
6400
  selectedSource && !loadingPreview && currentPreview.length === 0 && /* @__PURE__ */ jsx("a", { href: selectedSource.path, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsx(
6339
6401
  Button,
6340
6402
  {
6341
6403
  leftIcon: /* @__PURE__ */ jsx(IconExternalLink, { size: 16 }),
6342
6404
  fullWidth: true,
6343
- children: `Open ${selectedSource.title} response in a new window`
6405
+ children: translations["open_in_window"].replace("{src}", selectedSource.title)
6344
6406
  }
6345
6407
  ) }),
6346
6408
  selectedSource && !loadingPreview && currentPreview.length > 0 && /* @__PURE__ */ jsxs(Stack, { children: [
@@ -6354,7 +6416,7 @@ function DataTab(props) {
6354
6416
  }
6355
6417
  ),
6356
6418
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
6357
- /* @__PURE__ */ jsx(Input.Wrapper, { label: "Choose format:", children: /* @__PURE__ */ jsx(Button.Group, { children: Object.keys(formatOptions).map((format2) => /* @__PURE__ */ jsx(
6419
+ /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_format"]}:`, children: /* @__PURE__ */ jsx(Button.Group, { children: Object.keys(formatOptions).map((format2) => /* @__PURE__ */ jsx(
6358
6420
  Button,
6359
6421
  {
6360
6422
  leftIcon: /* @__PURE__ */ jsx(IconTable, { size: 16 }),
@@ -6372,7 +6434,7 @@ function DataTab(props) {
6372
6434
  loading: fileProcessing,
6373
6435
  onClick: onSaveClick,
6374
6436
  fullWidth: true,
6375
- children: /* @__PURE__ */ jsx("span", { children: fileProcessing ? "Processing file..." : `Download full dataset in ${fileFormat} format` })
6437
+ children: /* @__PURE__ */ jsx("span", { children: fileProcessing ? translations["processing_file"] : translations["download"].replace("{fmt}", fileFormat) })
6376
6438
  }
6377
6439
  )
6378
6440
  ] })
@@ -6443,6 +6505,15 @@ var formatOptions2 = {
6443
6505
  png: "PNG",
6444
6506
  svg: "SVG"
6445
6507
  };
6508
+ var DEFAULT_TRANSLATIONS3 = {
6509
+ "wrong_node": "Wrong node in export",
6510
+ "choose_area": "Choose image area",
6511
+ "choose_viz": "Choose visualization",
6512
+ "choose_format": "Choose format",
6513
+ "transparent_bg": "Transparent background",
6514
+ "processing": "Processing image...",
6515
+ "download": "Download {imageFormat}"
6516
+ };
6446
6517
  function ImageTab(props) {
6447
6518
  const { section } = props;
6448
6519
  const blocksIds = section.blocks || [];
@@ -6456,6 +6527,8 @@ function ImageTab(props) {
6456
6527
  const [vizSelected, setVizSelected] = useState(vizAvailable.length > 0 ? vizAvailable[0].id : null);
6457
6528
  const [transparentBackground, setTransparentBackground] = useState(true);
6458
6529
  const [loadingPreviews, setLoadingPreviews] = useState(false);
6530
+ const optionsTranslations = useBespokeTranslations("options");
6531
+ const translations = { ...DEFAULT_TRANSLATIONS3, ...optionsTranslations["image_tab"] };
6459
6532
  const vizSelectedHasSVG = () => {
6460
6533
  const vizNode = getVizNode(section.id, vizSelected);
6461
6534
  const svgCount = select(vizNode).select("svg").size();
@@ -6536,7 +6609,7 @@ function ImageTab(props) {
6536
6609
  if (node) {
6537
6610
  exportFunction(node, exportConfig);
6538
6611
  } else {
6539
- throw new Error("Wrong node in export");
6612
+ throw new Error(translations["wrong_node"]);
6540
6613
  }
6541
6614
  } catch (error) {
6542
6615
  setImageProcessing(false);
@@ -6572,7 +6645,7 @@ function ImageTab(props) {
6572
6645
  }, [vizSelected]);
6573
6646
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-image", children: [
6574
6647
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
6575
- /* @__PURE__ */ jsx(Input.Wrapper, { label: "Choose image area:", children: /* @__PURE__ */ jsxs(Button.Group, { children: [
6648
+ /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_area"]}:`, children: /* @__PURE__ */ jsxs(Button.Group, { children: [
6576
6649
  /* @__PURE__ */ jsx(
6577
6650
  Button,
6578
6651
  {
@@ -6600,12 +6673,13 @@ function ImageTab(props) {
6600
6673
  imageContext === contextOptions.viz && vizAvailable.length > 0 && /* @__PURE__ */ jsxs(
6601
6674
  Input.Wrapper,
6602
6675
  {
6603
- label: "Choose visualization:",
6676
+ label: `${translations["choose_viz"]}:`,
6604
6677
  style: { minHeight: "161px", position: "relative" },
6605
6678
  children: [
6606
6679
  !loadingPreviews && vizPreviews.length > 0 && /* @__PURE__ */ jsx(ScrollArea, { style: { height: 250 }, children: /* @__PURE__ */ jsx(SimpleGrid, { cols: 3, children: vizAvailable.map((vizOption, ix) => /* @__PURE__ */ jsx(
6607
6680
  Image,
6608
6681
  {
6682
+ alt: `Viz ${vizOption.id}`,
6609
6683
  onClick: () => {
6610
6684
  setVizSelected(vizOption.id);
6611
6685
  },
@@ -6623,7 +6697,7 @@ function ImageTab(props) {
6623
6697
  ]
6624
6698
  }
6625
6699
  ),
6626
- svgAvailable && imageContext !== contextOptions.section && /* @__PURE__ */ jsx(Input.Wrapper, { label: "Choose format:", children: /* @__PURE__ */ jsxs(Button.Group, { children: [
6700
+ svgAvailable && imageContext !== contextOptions.section && /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_format"]}:`, children: /* @__PURE__ */ jsxs(Button.Group, { children: [
6627
6701
  /* @__PURE__ */ jsx(
6628
6702
  Button,
6629
6703
  {
@@ -6649,7 +6723,7 @@ function ImageTab(props) {
6649
6723
  Checkbox,
6650
6724
  {
6651
6725
  checked: transparentBackground,
6652
- label: "Transparent background",
6726
+ label: `${translations["transparent_bg"]}:`,
6653
6727
  onChange: () => setTransparentBackground(!transparentBackground),
6654
6728
  radius: "xl"
6655
6729
  }
@@ -6661,7 +6735,7 @@ function ImageTab(props) {
6661
6735
  loading: imageProcessing,
6662
6736
  onClick: onSaveClick,
6663
6737
  fullWidth: true,
6664
- children: /* @__PURE__ */ jsx("span", { children: imageProcessing ? "Processing image..." : `Download ${imageFormat}` })
6738
+ children: /* @__PURE__ */ jsx("span", { children: imageProcessing ? translations["processing"] : translations["download"].replace("{imageFormat}", imageFormat) })
6665
6739
  }
6666
6740
  )
6667
6741
  ] });
@@ -6669,11 +6743,17 @@ function ImageTab(props) {
6669
6743
 
6670
6744
  // components/options/tabs/ShareTab.tsx
6671
6745
  init_esm_shims();
6746
+ var DEFAULT_TRANSLATIONS4 = {
6747
+ "title": "Title",
6748
+ "include_section": "Include Section"
6749
+ };
6672
6750
  function ShareTab(props) {
6673
6751
  const { section } = props;
6674
6752
  const [shareUrl, setShareUrl] = useState("");
6675
6753
  const [title, setTitle] = useState("");
6676
6754
  const [includeSection, setIncludeSection] = useState(true);
6755
+ const optionsTranslations = useBespokeTranslations("options");
6756
+ const translations = { ...DEFAULT_TRANSLATIONS4, ...optionsTranslations["share_tab"] };
6677
6757
  useEffect(() => {
6678
6758
  setTitle(document.title);
6679
6759
  const { origin, pathname } = window.location;
@@ -6683,12 +6763,12 @@ function ShareTab(props) {
6683
6763
  }, [includeSection]);
6684
6764
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-share", children: [
6685
6765
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
6686
- /* @__PURE__ */ jsx(CopyInput, { title: `Title: ${title}`, url: shareUrl }),
6766
+ /* @__PURE__ */ jsx(CopyInput, { title: `${translations["title"]}: ${title}`, url: shareUrl }),
6687
6767
  /* @__PURE__ */ jsx(
6688
6768
  Checkbox,
6689
6769
  {
6690
6770
  checked: includeSection,
6691
- label: "Include section",
6771
+ label: translations["include_section"],
6692
6772
  onChange: () => setIncludeSection(!includeSection),
6693
6773
  radius: "xl"
6694
6774
  }
@@ -6749,6 +6829,11 @@ function ShareTab(props) {
6749
6829
  ] })
6750
6830
  ] });
6751
6831
  }
6832
+ var DEFAULT_TRANSLATIONS5 = {
6833
+ download_title: "Download Data",
6834
+ image_title: "Save Image",
6835
+ share_title: "Share Link"
6836
+ };
6752
6837
  function OptionsModal(props) {
6753
6838
  const {
6754
6839
  section,
@@ -6758,11 +6843,13 @@ function OptionsModal(props) {
6758
6843
  title
6759
6844
  } = props;
6760
6845
  const [selectedTab, setSelectedTab] = useState(initialMode || "data");
6846
+ const optionsTranslations = useBespokeTranslations("options");
6761
6847
  useEffect(() => {
6762
6848
  if (initialMode !== selectedTab) {
6763
6849
  setSelectedTab(initialMode);
6764
6850
  }
6765
6851
  }, [initialMode]);
6852
+ const translations = { ...DEFAULT_TRANSLATIONS5, ...optionsTranslations };
6766
6853
  return /* @__PURE__ */ jsx("div", { className: "cms-section-options-modal", children: open && /* @__PURE__ */ jsx(
6767
6854
  Modal,
6768
6855
  {
@@ -6779,9 +6866,9 @@ function OptionsModal(props) {
6779
6866
  keepMounted: false,
6780
6867
  children: [
6781
6868
  /* @__PURE__ */ jsxs(Tabs.List, { children: [
6782
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "data", children: "Download data" }),
6783
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "image", children: "Save image" }),
6784
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "share", children: "Share link" })
6869
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "data", children: translations.download_title }),
6870
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "image", children: translations.image_title }),
6871
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "share", children: translations.share_title })
6785
6872
  ] }),
6786
6873
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "data", children: /* @__PURE__ */ jsx(DataTab, { section }) }),
6787
6874
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "image", children: /* @__PURE__ */ jsx(ImageTab, { section }) }),
@@ -6819,8 +6906,7 @@ function Options(props) {
6819
6906
  section: sectionRef.data,
6820
6907
  initialMode: mode,
6821
6908
  open: opened,
6822
- onEnds: onModalEnds,
6823
- title: "Section information"
6909
+ onEnds: onModalEnds
6824
6910
  }
6825
6911
  )
6826
6912
  ] });
@@ -7251,7 +7337,7 @@ var getBlockSettings = (blockType) => {
7251
7337
  return extraSettings;
7252
7338
  };
7253
7339
 
7254
- // cms/components/components/DesignMenu.tsx
7340
+ // components/builder/components/DesignMenu.tsx
7255
7341
  init_esm_shims();
7256
7342
  init_store2();
7257
7343
  var ALLOWED_UNITS = ["px", "%"];
@@ -7399,6 +7485,9 @@ function DesignMenu({ id, display = "button", handleChange }) {
7399
7485
  ) : /* @__PURE__ */ jsx(Paper, { p: "md", withBorder: true, children: menu });
7400
7486
  }
7401
7487
  var DesignMenu_default = DesignMenu;
7488
+ var DEFAULT_TRANSLATIONS6 = {
7489
+ "image_by": "image by"
7490
+ };
7402
7491
  var getStyles = (styles, settings) => (theme) => styles ? styles(theme, settings) : {};
7403
7492
  var PositionWrapper = ({ settings, styles, children, ...props }) => {
7404
7493
  const { position } = settings;
@@ -7468,6 +7557,8 @@ function Section({ section }) {
7468
7557
  const sectionStyles = useBespokeStyles()["Section"];
7469
7558
  const blockRecords = selectBlockRecords(state);
7470
7559
  const sectionBlocks = Object.values(blockRecords || {}).filter((d) => d.section_id === id);
7560
+ const sectionTranslations = useBespokeTranslations("sections");
7561
+ const translations = { ...DEFAULT_TRANSLATIONS6, ...sectionTranslations };
7471
7562
  const allowedSection = sectionBlocks.some((b) => {
7472
7563
  try {
7473
7564
  return status[b.id].allowed && b.type !== BLOCK_TYPES.GENERATOR || b.type === BLOCK_TYPES.NAV;
@@ -7566,7 +7657,9 @@ function Section({ section }) {
7566
7657
  ({ image, name }, idx) => (image.author || image.url) && /* @__PURE__ */ jsxs("div", { children: [
7567
7658
  image.author && /* @__PURE__ */ jsxs(Text, { size: "xs", children: [
7568
7659
  name,
7569
- " image by ",
7660
+ " ",
7661
+ translations["image_by"],
7662
+ " ",
7570
7663
  /* @__PURE__ */ jsx("strong", { children: image.author })
7571
7664
  ] }),
7572
7665
  image.url && /* @__PURE__ */ jsxs(Text, { size: "xs", children: [
@@ -9337,7 +9430,7 @@ init_esm_shims();
9337
9430
  // components/blocks/BlockElement.tsx
9338
9431
  init_esm_shims();
9339
9432
 
9340
- // cms/components/components/DeleteButton.tsx
9433
+ // components/builder/components/DeleteButton.tsx
9341
9434
  init_esm_shims();
9342
9435
  init_store2();
9343
9436
  init_cms();
@@ -9369,7 +9462,7 @@ init_store2();
9369
9462
  init_esm_shims();
9370
9463
  init_cms();
9371
9464
 
9372
- // cms/components/components/ApiInput.tsx
9465
+ // components/builder/components/ApiInput.tsx
9373
9466
  init_esm_shims();
9374
9467
  init_varSwap();
9375
9468
  init_hooks();
@@ -9451,7 +9544,7 @@ function ApiInput({
9451
9544
  }
9452
9545
  var ApiInput_default = ApiInput;
9453
9546
 
9454
- // cms/editors/MonacoWrapper.tsx
9547
+ // components/builder/editors/MonacoWrapper.tsx
9455
9548
  init_esm_shims();
9456
9549
  function MonacoWrapper({ monacoOptions, variables = {} }) {
9457
9550
  const monaco = useMonaco();
@@ -9855,7 +9948,7 @@ function BlockSettings({ id, setBlockSettings, setBlockContent }) {
9855
9948
  }
9856
9949
  var BlockSettings_default = BlockSettings;
9857
9950
 
9858
- // cms/components/components/InputMenu.tsx
9951
+ // components/builder/components/InputMenu.tsx
9859
9952
  init_esm_shims();
9860
9953
  init_store2();
9861
9954
  init_actions();
@@ -9982,16 +10075,16 @@ function InputMenu({ id }) {
9982
10075
  }
9983
10076
  var InputMenu_default = InputMenu;
9984
10077
 
9985
- // cms/editors/SimpleUI.tsx
10078
+ // components/builder/editors/SimpleUI.tsx
9986
10079
  init_esm_shims();
9987
10080
  init_hooks();
9988
10081
  init_cms();
9989
10082
 
9990
- // cms/editors/RichTextEditor.tsx
10083
+ // components/builder/editors/RichTextEditor.tsx
9991
10084
  init_esm_shims();
9992
10085
  init_store2();
9993
10086
 
9994
- // cms/editors/MCEWrapper.tsx
10087
+ // components/builder/editors/MCEWrapper.tsx
9995
10088
  init_esm_shims();
9996
10089
  function MCEWrapper({
9997
10090
  initialValue,
@@ -10039,7 +10132,7 @@ function MCEWrapper({
10039
10132
  }
10040
10133
  var MCEWrapper_default = MCEWrapper;
10041
10134
 
10042
- // cms/editors/RichTextEditor.tsx
10135
+ // components/builder/editors/RichTextEditor.tsx
10043
10136
  init_sanitizeBlockContent();
10044
10137
 
10045
10138
  // libs/js/deepClone.ts
@@ -10503,7 +10596,7 @@ function BlockEditor({
10503
10596
  }
10504
10597
  var BlockEditor_default = BlockEditor;
10505
10598
 
10506
- // cms/components/components/ConsumerMenu.tsx
10599
+ // components/builder/components/ConsumerMenu.tsx
10507
10600
  init_esm_shims();
10508
10601
  init_store2();
10509
10602
  function ConsumerMenu({ id }) {
@@ -13912,6 +14005,7 @@ init_esm_shims();
13912
14005
  init_ResourceProvider();
13913
14006
  function BespokeRenderer({
13914
14007
  pathSegmentsKey = "bespoke",
14008
+ translations,
13915
14009
  bespokeStyles,
13916
14010
  buildTime,
13917
14011
  profilePrefix = "/defaultPath"
@@ -13920,7 +14014,7 @@ function BespokeRenderer({
13920
14014
  if (loading)
13921
14015
  return /* @__PURE__ */ jsx(LoadingOverlay, { visible: true });
13922
14016
  return /* @__PURE__ */ jsx(MantineProvider, { theme: { other: { bespokeStyles } }, inherit: true, children: /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment: "bespoke", profilePrefix, children: [
13923
- /* @__PURE__ */ jsx(Report_default, {}),
14017
+ /* @__PURE__ */ jsx(TranslationsProvider, { translations, children: /* @__PURE__ */ jsx(Report_default, {}) }),
13924
14018
  /* @__PURE__ */ jsx("small", { children: buildTime })
13925
14019
  ] }) });
13926
14020
  }
package/dist/server.js CHANGED
@@ -3376,7 +3376,7 @@ function endpointCRUDFactory(api, entity) {
3376
3376
  return crudUpdate(body);
3377
3377
  }, [CMS_ROLES.EDITOR]),
3378
3378
  endpoint("DELETE", `delete/${entity}`, (req) => {
3379
- const id = parseFiniteNumber(req.body.id);
3379
+ const id = parseFiniteNumber(req.query.id);
3380
3380
  return crudDelete(id);
3381
3381
  }, [CMS_ROLES.EDITOR])
3382
3382
  ];
@@ -3747,7 +3747,7 @@ async function endpointNextJsHandlerFactory(req, res) {
3747
3747
  return res.status(404).json({ error: "No matching route", path, query });
3748
3748
  }
3749
3749
 
3750
- // cms/crosswalk/index.ts
3750
+ // api/crosswalk/index.ts
3751
3751
  var reportsCrosswalkEntrypointFn = (crosswalk) => {
3752
3752
  const crosswalkFn = crosswalk;
3753
3753
  return async function(req, res) {
@@ -3821,11 +3821,13 @@ function httpPOST(axios6, request, transformPayload) {
3821
3821
  }
3822
3822
  function httpDELETE(axios6, request, transformPayload) {
3823
3823
  const config = typeof request === "string" ? { url: request } : request;
3824
- return (payload) => http(axios6, {
3825
- ...config,
3826
- method: "DELETE",
3827
- data: transformPayload ? transformPayload(payload) : payload
3828
- });
3824
+ return (payload) => {
3825
+ return http(axios6, {
3826
+ ...config,
3827
+ method: "DELETE",
3828
+ params: transformPayload ? transformPayload(payload) : payload
3829
+ });
3830
+ };
3829
3831
  }
3830
3832
 
3831
3833
  // api/http/image/imageSave.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/bespoke",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Content management system for creating automated data reports",
5
5
  "exports": {
6
6
  ".": {
@@ -125,6 +125,6 @@
125
125
  "tsup": "^6.6.0"
126
126
  },
127
127
  "peerDependencies": {
128
- "next": "13.2.0"
128
+ "next": "^13.4.0"
129
129
  }
130
130
  }