@datawheel/bespoke 0.3.20 → 0.3.22

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.js CHANGED
@@ -2957,16 +2957,17 @@ var init_actions = __esm({
2957
2957
  }
2958
2958
  });
2959
2959
  function ResourceProvider(props) {
2960
- const { pathSegment, profilePrefix } = props;
2960
+ const { pathSegment, profilePrefix, siteProps } = props;
2961
2961
  const formatters2 = useFormatterList();
2962
2962
  const value = useMemo(() => ({
2963
2963
  profilePrefix,
2964
2964
  pathSegment,
2965
+ siteProps,
2965
2966
  formatterFunctions: locales3.reduce((acc, locale) => ({
2966
2967
  ...acc,
2967
2968
  [locale]: formatters2.data ? funcifyFormattersByLocale(formatters2.data, locale) : {}
2968
2969
  }), {})
2969
- }), [formatters2, pathSegment, profilePrefix]);
2970
+ }), [formatters2, pathSegment, profilePrefix, siteProps]);
2970
2971
  return /* @__PURE__ */ jsx(ResourceContext.Provider, { value, children: props.children });
2971
2972
  }
2972
2973
  function useBespoke() {
@@ -2987,7 +2988,8 @@ var init_ResourceProvider = __esm({
2987
2988
  initialContext = {
2988
2989
  pathSegment: "path",
2989
2990
  formatterFunctions: locales3.reduce((acc, d) => ({ ...acc, [d]: {} }), {}),
2990
- profilePrefix: "path"
2991
+ profilePrefix: "path",
2992
+ siteProps: {}
2991
2993
  };
2992
2994
  ResourceContext = createContext(initialContext);
2993
2995
  }
@@ -8029,41 +8031,69 @@ var init_DataTab = __esm({
8029
8031
  function ImageTab(props) {
8030
8032
  const { section } = props;
8031
8033
  const blocksIds = section.blocks || [];
8032
- const vizBlocks = useAppSelector((state) => blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => block.type === "visualization" && state.variables.status[block.id].allowed));
8034
+ const vizAvailable = useAppSelector((state) => blocksIds.map((blockId) => state.records.entities.block[blockId]).filter((block) => block.type === "visualization" && state.variables.status[block.id].allowed));
8033
8035
  const [imageContext, setImageContext] = useState(contextOptions.section);
8034
8036
  const [imageFormat, setImageFormat] = useState(formatOptions2.png);
8035
8037
  const [imageProcessing, setImageProcessing] = useState(false);
8036
8038
  const [svgAvailable, setSvgAvailable] = useState(false);
8037
- const [vizAvailable, setVizAvailable] = useState(vizBlocks);
8038
8039
  const [vizPreviews, setVizPreviews] = useState([]);
8039
8040
  const [vizSelected, setVizSelected] = useState(vizAvailable.length > 0 ? vizAvailable[0].id : null);
8040
8041
  const [transparentBackground, setTransparentBackground] = useState(true);
8041
8042
  const [loadingPreviews, setLoadingPreviews] = useState(false);
8042
8043
  const optionsTranslations = useBespokeTranslations("options");
8043
8044
  const translations = { ...DEFAULT_TRANSLATIONS3, ...optionsTranslations["image_tab"] };
8045
+ const { siteProps } = useBespoke();
8046
+ const includeLogo = siteProps?.logoSrc && typeof siteProps.logoSrc === "string";
8047
+ const sectionId = section?.settings?.name || `section-${section.id}`;
8048
+ const sectionHash = `#${sectionId}`;
8049
+ const theme = useMantineTheme();
8044
8050
  const vizSelectedHasSVG = () => {
8045
- const vizNode = getVizNode(section.id, vizSelected);
8051
+ const vizNode = getVizNode(vizSelected);
8046
8052
  const svgCount = select(vizNode).select("svg").size();
8047
8053
  return svgCount === 1;
8048
8054
  };
8049
- const getFileName = () => `${slugify_default("export-name")}`;
8050
- const getSectionNode = (sectionId) => {
8051
- const sectionNode = document.getElementById(`section-${sectionId}`);
8055
+ const getFileName = () => `${slugify_default(sectionId)}`;
8056
+ const getSectionNode = () => {
8057
+ const sectionNode = document.getElementById(sectionId);
8052
8058
  return select(sectionNode).select(".bespoke-section-content").node();
8053
8059
  };
8054
- const getVizNode = (sectionId, vizId) => {
8055
- const sectionNode = getSectionNode(sectionId);
8060
+ const getVizNode = (vizId) => {
8061
+ const sectionNode = getSectionNode();
8056
8062
  return select(sectionNode).select(`#bespoke-visualization-${vizId}.bespoke-block-area`).node();
8057
8063
  };
8058
- const getSelectedNode = () => {
8064
+ const getSelectedNode = () => new Promise((resolve) => {
8059
8065
  let node;
8060
8066
  if (imageContext === contextOptions.section) {
8061
- node = getSectionNode(section.id);
8067
+ node = getSectionNode();
8062
8068
  } else if (imageContext === contextOptions.viz) {
8063
- node = getVizNode(section.id, vizSelected);
8069
+ node = getVizNode(vizSelected);
8064
8070
  }
8065
- return node;
8066
- };
8071
+ const sourceContainer = document.createElement("div");
8072
+ sourceContainer.style.display = "flex";
8073
+ sourceContainer.style.justifyContent = "space-between";
8074
+ sourceContainer.classList.add("bespoke-Viz-source");
8075
+ sourceContainer.style.padding = theme.spacing.xs;
8076
+ sourceContainer.style.width = "100%";
8077
+ const sourceNode = document.createElement("div");
8078
+ sourceNode.innerText = translations["source"].replace("{src}", `${window.location}${sectionHash}`);
8079
+ sourceNode.style.fontSize = theme.fontSizes.xs;
8080
+ sourceContainer.appendChild(sourceNode);
8081
+ if (includeLogo) {
8082
+ const sourceImage = document.createElement("img");
8083
+ sourceImage.src = siteProps.logoSrc;
8084
+ sourceImage.style.height = "30px";
8085
+ sourceImage.onload = () => resolve(node);
8086
+ sourceImage.onerror = () => {
8087
+ sourceImage.remove();
8088
+ resolve(node);
8089
+ };
8090
+ sourceContainer.appendChild(sourceImage);
8091
+ node.appendChild(sourceContainer);
8092
+ } else {
8093
+ node.appendChild(sourceContainer);
8094
+ resolve(node);
8095
+ }
8096
+ });
8067
8097
  const getBackground = (elem) => {
8068
8098
  if (transparentBackground)
8069
8099
  return "transparent";
@@ -8086,9 +8116,6 @@ function ImageTab(props) {
8086
8116
  return !config.exclusionClasses.some((classname) => innerNode.classList.contains(classname));
8087
8117
  }
8088
8118
  return true;
8089
- },
8090
- style: {
8091
- // background: "green",
8092
8119
  }
8093
8120
  }
8094
8121
  ).then((dataUrl) => {
@@ -8096,6 +8123,7 @@ function ImageTab(props) {
8096
8123
  link.download = `${config.filename}.png`;
8097
8124
  link.href = dataUrl;
8098
8125
  link.click();
8126
+ cleanDOM();
8099
8127
  setImageProcessing(false);
8100
8128
  }).catch((err) => {
8101
8129
  console.log(err);
@@ -8108,9 +8136,9 @@ function ImageTab(props) {
8108
8136
  { background: config.background }
8109
8137
  );
8110
8138
  };
8111
- const onSaveClick = () => {
8139
+ const onSaveClick = async () => {
8112
8140
  setImageProcessing(true);
8113
- const node = getSelectedNode();
8141
+ const node = await getSelectedNode();
8114
8142
  const exportConfig = {
8115
8143
  background: getBackground(node),
8116
8144
  exclusionClasses: ["export-hidden"],
@@ -8130,7 +8158,7 @@ function ImageTab(props) {
8130
8158
  const generatePreviews = async () => {
8131
8159
  const { toCanvas } = await import('html-to-image');
8132
8160
  Promise.all(
8133
- vizAvailable.map((viz) => toCanvas(getVizNode(section.id, viz.id)))
8161
+ vizAvailable.map((viz) => toCanvas(getVizNode(viz.id)))
8134
8162
  ).then((canvases) => {
8135
8163
  setVizPreviews(canvases.map((canvas) => canvas.toDataURL()));
8136
8164
  setLoadingPreviews(false);
@@ -8157,7 +8185,7 @@ function ImageTab(props) {
8157
8185
  }, [vizSelected]);
8158
8186
  return /* @__PURE__ */ jsxs(Stack, { className: "cms-section-options-image", children: [
8159
8187
  /* @__PURE__ */ jsx(Space, { h: "xs" }),
8160
- /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_area"]}:`, children: /* @__PURE__ */ jsx(
8188
+ vizAvailable.length > 0 ? /* @__PURE__ */ jsx(Input.Wrapper, { label: `${translations["choose_area"]}:`, children: /* @__PURE__ */ jsx(
8161
8189
  SegmentedControl,
8162
8190
  {
8163
8191
  fullWidth: true,
@@ -8185,7 +8213,7 @@ function ImageTab(props) {
8185
8213
  }
8186
8214
  }
8187
8215
  }
8188
- ) }),
8216
+ ) }) : /* @__PURE__ */ jsx(Text, { fw: "700", color: "gray.7", children: `${translations["entire_section"]}:` }),
8189
8217
  imageContext === contextOptions.viz && vizAvailable.length > 0 && /* @__PURE__ */ jsxs(
8190
8218
  Input.Wrapper,
8191
8219
  {
@@ -8239,7 +8267,7 @@ function ImageTab(props) {
8239
8267
  Checkbox,
8240
8268
  {
8241
8269
  checked: transparentBackground,
8242
- label: `${translations["transparent_bg"]}:`,
8270
+ label: `${translations["transparent_bg"]}`,
8243
8271
  onChange: () => setTransparentBackground(!transparentBackground),
8244
8272
  radius: "xl"
8245
8273
  }
@@ -8256,13 +8284,14 @@ function ImageTab(props) {
8256
8284
  )
8257
8285
  ] });
8258
8286
  }
8259
- var contextOptions, formatOptions2, DEFAULT_TRANSLATIONS3;
8287
+ var contextOptions, formatOptions2, cleanDOM, DEFAULT_TRANSLATIONS3;
8260
8288
  var init_ImageTab = __esm({
8261
8289
  "components/options/tabs/ImageTab.tsx"() {
8262
8290
  init_esm_shims();
8263
8291
  init_slugify();
8264
8292
  init_store2();
8265
8293
  init_TranslationsProvider();
8294
+ init_ResourceProvider();
8266
8295
  contextOptions = {
8267
8296
  viz: "viz",
8268
8297
  section: "section"
@@ -8271,6 +8300,10 @@ var init_ImageTab = __esm({
8271
8300
  png: "PNG",
8272
8301
  svg: "SVG"
8273
8302
  };
8303
+ cleanDOM = () => {
8304
+ const sourceNodes = document.getElementsByClassName("bespoke-Viz-source");
8305
+ Array.from(sourceNodes).forEach((node) => node.remove());
8306
+ };
8274
8307
  DEFAULT_TRANSLATIONS3 = {
8275
8308
  "wrong_node": "Wrong node in export",
8276
8309
  "choose_area": "Choose image area",
@@ -8280,7 +8313,8 @@ var init_ImageTab = __esm({
8280
8313
  "processing": "Processing image...",
8281
8314
  "download": "Download {imageFormat}",
8282
8315
  "entire_section": "Entire section",
8283
- "viz_only": "Visualization only"
8316
+ "viz_only": "Visualization only",
8317
+ "source": "Source: {src}"
8284
8318
  };
8285
8319
  }
8286
8320
  });
@@ -9181,6 +9215,7 @@ var init_ImageCredits = __esm({
9181
9215
  }
9182
9216
  });
9183
9217
  function SectionWrapper({
9218
+ name,
9184
9219
  children,
9185
9220
  id,
9186
9221
  sectionSettings: sectionSettings2,
@@ -9204,7 +9239,7 @@ function SectionWrapper({
9204
9239
  className: `bespoke-Section-${id} bespoke-Section-container `,
9205
9240
  settings: sectionSettings2,
9206
9241
  styles: sectionStyles?.container,
9207
- id: `section-${id}`,
9242
+ id: name || `section-${id}`,
9208
9243
  pos: "relative",
9209
9244
  children: [
9210
9245
  !print && /* @__PURE__ */ jsxs(Group, { position: "right", mb: "xs", children: [
@@ -9356,6 +9391,7 @@ function Section({ section }) {
9356
9391
  SectionWrapper,
9357
9392
  {
9358
9393
  id,
9394
+ name: section?.settings?.name,
9359
9395
  previews: comparisonPreviews,
9360
9396
  sectionSettings: sectionSettings2,
9361
9397
  sectionStyles,
@@ -16677,6 +16713,7 @@ function BespokeRenderer({
16677
16713
  translations,
16678
16714
  bespokeStyles,
16679
16715
  buildTime,
16716
+ siteProps,
16680
16717
  profilePrefix = "/defaultPath",
16681
16718
  loader = /* @__PURE__ */ jsx(LoadingOverlay, { visible: true }),
16682
16719
  mantineProviderProps = {}
@@ -16684,7 +16721,7 @@ function BespokeRenderer({
16684
16721
  const loading = useInitialState(pathSegmentsKey);
16685
16722
  if (loading)
16686
16723
  return /* @__PURE__ */ jsx(Fragment, { children: loader });
16687
- return /* @__PURE__ */ jsx(MantineProvider, { ...mantineProviderProps, theme: { other: { bespokeStyles } }, inherit: true, children: /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment: "bespoke", profilePrefix, children: [
16724
+ return /* @__PURE__ */ jsx(MantineProvider, { ...mantineProviderProps, theme: { other: { bespokeStyles } }, inherit: true, children: /* @__PURE__ */ jsxs(ResourceProvider, { pathSegment: "bespoke", profilePrefix, siteProps, children: [
16688
16725
  /* @__PURE__ */ jsx(TranslationsProvider, { translations, children: /* @__PURE__ */ jsx(ComparisonProvider, { children: /* @__PURE__ */ jsx(PdfProvider, { children: /* @__PURE__ */ jsx(Report_default, {}) }) }) }),
16689
16726
  /* @__PURE__ */ jsx("small", { className: "bespoke-timestamp", children: buildTime })
16690
16727
  ] }) });
package/dist/server.js CHANGED
@@ -5900,7 +5900,8 @@ var { locales: locales8 } = getLocales_default();
5900
5900
  var initialContext = {
5901
5901
  pathSegment: "path",
5902
5902
  formatterFunctions: locales8.reduce((acc, d) => ({ ...acc, [d]: {} }), {}),
5903
- profilePrefix: "path"
5903
+ profilePrefix: "path",
5904
+ siteProps: {}
5904
5905
  };
5905
5906
  createContext(initialContext);
5906
5907
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/bespoke",
3
- "version": "0.3.20",
3
+ "version": "0.3.22",
4
4
  "description": "Content management system for creating automated data reports",
5
5
  "exports": {
6
6
  ".": {
@@ -130,4 +130,4 @@
130
130
  "peerDependencies": {
131
131
  "next": "^13.4.0"
132
132
  }
133
- }
133
+ }