@valu/block-components 0.3.1 → 0.4.0

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/README.md CHANGED
@@ -46,6 +46,10 @@ function Edit({ attributes, setAttributes }) {
46
46
  - [`ContentPicker`](components/content-picker/readme.md) — search and
47
47
  select posts, pages, users, or taxonomy terms with drag-to-reorder,
48
48
  thumbnails, status/type badges, and grouped results.
49
+ - [`DocumentPicker`](components/document-picker/readme.md) — attach
50
+ document attachments (PDF, Word, Excel, PowerPoint by default) via
51
+ REST search-as-you-type combined with the native Media Library modal,
52
+ with optional in-place editable display names per item.
49
53
  - [`Matrix`](components/matrix/readme.md) — abstract row × column grid of
50
54
  selectable cells with optional collapsible column groups and a sticky
51
55
  master gate column. For permission matrices, feature-flag grids,
@@ -558,6 +558,54 @@ var DocMetaInline = styled__default.default.div`
558
558
  white-space: nowrap;
559
559
  }
560
560
  `;
561
+ var ReorderButtons = styled__default.default.span`
562
+ display: none;
563
+
564
+ @container valu-dp-row (min-width: 340px) {
565
+ display: inline-flex;
566
+ }
567
+ `;
568
+ var LabelEditBody = styled__default.default.div`
569
+ flex: 1;
570
+ min-width: 0;
571
+ display: flex;
572
+ flex-direction: column;
573
+ gap: 2px;
574
+ padding: 4px 0;
575
+
576
+ .components-base-control,
577
+ .components-text-control__input {
578
+ width: 100%;
579
+ min-width: 0;
580
+ }
581
+
582
+ /* __nextHasNoMarginBottom is not honored by every bundled
583
+ wp-components version — enforce the no-margin layout here. */
584
+ .components-base-control.components-base-control {
585
+ margin-bottom: 0;
586
+ }
587
+
588
+ /* Doubled class beats wp-components' own input rules regardless of
589
+ stylesheet order (the emotion cache may be prepended). */
590
+ .components-text-control__input.components-text-control__input {
591
+ font-size: ${tokens.fontSizeBody};
592
+ height: 28px;
593
+ min-height: 28px;
594
+ padding: 2px 8px;
595
+ }
596
+
597
+ @container valu-dp-row (min-width: ${WIDE_ROW}) {
598
+ flex-direction: row;
599
+ align-items: center;
600
+ gap: ${tokens.spaceMd};
601
+
602
+ .components-base-control {
603
+ flex: 0 1 340px;
604
+ min-width: 180px;
605
+ width: auto;
606
+ }
607
+ }
608
+ `;
561
609
  var Root2 = styled__default.default.div`
562
610
  color: ${tokens.fg};
563
611
  font-size: ${tokens.fontSizeBody};
@@ -718,6 +766,7 @@ var mapMediaToDocumentItem = (raw) => {
718
766
  raw
719
767
  };
720
768
  };
769
+ var displayTitle = (item) => item.label?.trim() || item.title;
721
770
  var dedupeAgainst = (items, value, enabled) => {
722
771
  if (!enabled || value.length === 0) return items;
723
772
  const ids = new Set(value.map((v) => v.id));
@@ -1722,6 +1771,8 @@ var SelectedItem = ({
1722
1771
  onRemove,
1723
1772
  onMoveUp,
1724
1773
  onMoveDown,
1774
+ enableLabelEdit = false,
1775
+ onLabelChange,
1725
1776
  render
1726
1777
  }) => {
1727
1778
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = sortable.useSortable({
@@ -1735,22 +1786,46 @@ var SelectedItem = ({
1735
1786
  };
1736
1787
  const isMissing = item.missing === "deleted";
1737
1788
  const missingLabel = labels.missing ?? i18n.__("This document is no longer available.", "valu-block-components");
1789
+ const displayName = displayTitle(item);
1738
1790
  const removeLabel = labels.remove ? labels.remove : i18n.sprintf(
1739
1791
  /* translators: %s: document title */
1740
1792
  i18n.__("Remove %s", "valu-block-components"),
1741
- item.title
1793
+ displayName
1742
1794
  );
1743
1795
  const moveUpLabel = labels.moveUp ? labels.moveUp : i18n.sprintf(
1744
1796
  /* translators: %s: document title */
1745
1797
  i18n.__("Move %s up", "valu-block-components"),
1746
- item.title
1798
+ displayName
1747
1799
  );
1748
1800
  const moveDownLabel = labels.moveDown ? labels.moveDown : i18n.sprintf(
1749
1801
  /* translators: %s: document title */
1750
1802
  i18n.__("Move %s down", "valu-block-components"),
1751
- item.title
1803
+ displayName
1752
1804
  );
1753
1805
  const modified = showModifiedDate ? formatModified(item.modified) : "";
1806
+ const isLabelEdit = enableLabelEdit && !isMissing && Boolean(onLabelChange);
1807
+ const [labelDraft, setLabelDraft] = react$1.useState(null);
1808
+ const commitTimer = react$1.useRef(null);
1809
+ react$1.useEffect(
1810
+ () => () => {
1811
+ if (commitTimer.current) {
1812
+ clearTimeout(commitTimer.current);
1813
+ }
1814
+ },
1815
+ []
1816
+ );
1817
+ const normalizeLabel = (value) => {
1818
+ const trimmed = value.trim();
1819
+ return trimmed === "" || trimmed === item.title ? "" : value;
1820
+ };
1821
+ const itemLabelText = labels.itemLabel ?? i18n.__("Display name", "valu-block-components");
1822
+ const metaParts = [item.filename];
1823
+ if (showFileSize && item.fileSize) {
1824
+ metaParts.push(formatFileSize(item.fileSize));
1825
+ }
1826
+ if (modified) {
1827
+ metaParts.push(modified);
1828
+ }
1754
1829
  return /* @__PURE__ */ jsxRuntime.jsxs(
1755
1830
  SelectedRow2,
1756
1831
  {
@@ -1772,9 +1847,45 @@ var SelectedItem = ({
1772
1847
  }
1773
1848
  ) : null,
1774
1849
  isMissing ? /* @__PURE__ */ jsxRuntime.jsx(components.Icon, { icon: icons.caution, size: 20 }) : showExtensionBadge ? /* @__PURE__ */ jsxRuntime.jsx(ExtensionBadge, { extension: item.extension }) : null,
1775
- render ? render(item) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1850
+ render ? render(item) : isLabelEdit ? /* @__PURE__ */ jsxRuntime.jsxs(LabelEditBody, { children: [
1851
+ /* @__PURE__ */ jsxRuntime.jsx(
1852
+ components.TextControl,
1853
+ {
1854
+ __nextHasNoMarginBottom: true,
1855
+ __next40pxDefaultSize: false,
1856
+ "aria-label": i18n.sprintf(
1857
+ /* translators: 1: display-name field label, 2: filename */
1858
+ "%1$s: %2$s",
1859
+ itemLabelText,
1860
+ item.filename
1861
+ ),
1862
+ value: labelDraft ?? item.label ?? item.title,
1863
+ onChange: (value) => {
1864
+ setLabelDraft(value);
1865
+ if (commitTimer.current) {
1866
+ clearTimeout(commitTimer.current);
1867
+ }
1868
+ commitTimer.current = setTimeout(() => {
1869
+ commitTimer.current = null;
1870
+ onLabelChange?.(normalizeLabel(value));
1871
+ }, 300);
1872
+ },
1873
+ onBlur: () => {
1874
+ if (commitTimer.current) {
1875
+ clearTimeout(commitTimer.current);
1876
+ commitTimer.current = null;
1877
+ if (labelDraft !== null) {
1878
+ onLabelChange?.(normalizeLabel(labelDraft));
1879
+ }
1880
+ }
1881
+ setLabelDraft(null);
1882
+ }
1883
+ }
1884
+ ),
1885
+ /* @__PURE__ */ jsxRuntime.jsx(FilenameText, { title: item.filename, children: metaParts.join(" \xB7 ") })
1886
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1776
1887
  /* @__PURE__ */ jsxRuntime.jsxs(DocRowBody, { children: [
1777
- /* @__PURE__ */ jsxRuntime.jsx(PrimaryText, { muted: isMissing, title: item.title, children: isMissing ? missingLabel : item.title }),
1888
+ /* @__PURE__ */ jsxRuntime.jsx(PrimaryText, { muted: isMissing, title: displayName, children: isMissing ? missingLabel : displayName }),
1778
1889
  !isMissing ? /* @__PURE__ */ jsxRuntime.jsx(FilenameText, { title: item.filename, children: item.filename }) : null
1779
1890
  ] }),
1780
1891
  !isMissing && (showFileSize || modified) ? /* @__PURE__ */ jsxRuntime.jsxs(DocMetaInline, { children: [
@@ -1783,7 +1894,7 @@ var SelectedItem = ({
1783
1894
  ] }) : null
1784
1895
  ] }),
1785
1896
  /* @__PURE__ */ jsxRuntime.jsxs(ActionColumn, { children: [
1786
- orderable ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1897
+ orderable ? /* @__PURE__ */ jsxRuntime.jsxs(ReorderButtons, { children: [
1787
1898
  /* @__PURE__ */ jsxRuntime.jsx(
1788
1899
  components.Button,
1789
1900
  {
@@ -1879,7 +1990,8 @@ var SelectedList = ({
1879
1990
  showHeader = true,
1880
1991
  showExtensionBadge,
1881
1992
  showFileSize,
1882
- showModifiedDate
1993
+ showModifiedDate,
1994
+ enableItemLabels = false
1883
1995
  }) => {
1884
1996
  const resolved = useResolvedDocuments(value);
1885
1997
  const [activeKey, setActiveKey] = react$1.useState(null);
@@ -1894,6 +2006,22 @@ var SelectedList = ({
1894
2006
  (key) => onChange(value.filter((i) => i.key !== key)),
1895
2007
  [value, onChange]
1896
2008
  );
2009
+ const setLabel = react$1.useCallback(
2010
+ (key, label) => onChange(
2011
+ value.map((i) => {
2012
+ if (i.key !== key) {
2013
+ return i;
2014
+ }
2015
+ if (label === "") {
2016
+ const rest = { ...i };
2017
+ delete rest.label;
2018
+ return rest;
2019
+ }
2020
+ return { ...i, label };
2021
+ })
2022
+ ),
2023
+ [value, onChange]
2024
+ );
1897
2025
  const reorder = react$1.useCallback(
1898
2026
  (from, to) => {
1899
2027
  if (from === to) return;
@@ -1942,6 +2070,10 @@ var SelectedList = ({
1942
2070
  onRemove: () => remove(item.key),
1943
2071
  ...index > 0 ? { onMoveUp: () => reorder(index, index - 1) } : {},
1944
2072
  ...index < resolved.length - 1 ? { onMoveDown: () => reorder(index, index + 1) } : {},
2073
+ ...enableItemLabels ? {
2074
+ enableLabelEdit: true,
2075
+ onLabelChange: (label) => setLabel(item.key, label)
2076
+ } : {},
1945
2077
  ...renderSelected ? { render: renderSelected } : {}
1946
2078
  },
1947
2079
  item.key
@@ -1964,7 +2096,7 @@ var SelectedList = ({
1964
2096
  onDragCancel: () => setActiveKey(null),
1965
2097
  children: [
1966
2098
  /* @__PURE__ */ jsxRuntime.jsx(sortable.SortableContext, { items: ids, strategy: sortable.verticalListSortingStrategy, children: /* @__PURE__ */ jsxRuntime.jsx(SelectedListEl, { role: "list", children: rows }) }),
1967
- /* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { dropAnimation: core.defaultDropAnimation, children: activeItem ? /* @__PURE__ */ jsxRuntime.jsx(DragChip, { title: activeItem.title }) : null })
2099
+ /* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { dropAnimation: core.defaultDropAnimation, children: activeItem ? /* @__PURE__ */ jsxRuntime.jsx(DragChip, { title: displayTitle(activeItem) }) : null })
1968
2100
  ]
1969
2101
  }
1970
2102
  )
@@ -1995,6 +2127,7 @@ var DocumentPicker = ({
1995
2127
  fetchOnOpen = false,
1996
2128
  uniqueItems = true,
1997
2129
  enableMediaLibrary = true,
2130
+ enableItemLabels = false,
1998
2131
  showExtensionBadge = true,
1999
2132
  showFileSize = true,
2000
2133
  showModifiedDate = false,
@@ -2086,7 +2219,14 @@ var DocumentPicker = ({
2086
2219
  ...allowedExtensions !== void 0 ? { allowedExtensions } : {},
2087
2220
  multiple: false,
2088
2221
  value,
2089
- onSelect: (items) => handleChange([items[items.length - 1]]),
2222
+ onSelect: (items) => {
2223
+ const next = items[items.length - 1];
2224
+ const prev = value[0];
2225
+ const keepLabel = prev?.id === next.id && prev.label !== void 0;
2226
+ handleChange([
2227
+ keepLabel ? { ...next, label: prev.label } : next
2228
+ ]);
2229
+ },
2090
2230
  labels,
2091
2231
  variant: "tertiary",
2092
2232
  label: labels.replace
@@ -2104,7 +2244,8 @@ var DocumentPicker = ({
2104
2244
  showHeader: value.length > 0,
2105
2245
  showExtensionBadge,
2106
2246
  showFileSize,
2107
- showModifiedDate
2247
+ showModifiedDate,
2248
+ enableItemLabels
2108
2249
  }
2109
2250
  )
2110
2251
  ] }) }) });