tinacms 3.14.3 → 3.15.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.
@@ -1,6 +1,9 @@
1
+ import type { TinaCMS } from '@tinacms/toolkit';
1
2
  import React from 'react';
2
3
  export declare const ErrorDialog: (props: {
3
- title: string;
4
+ /** @deprecated Pass the title to `cms.alerts.error` so it shows in the modal header. */
5
+ title?: string;
4
6
  message: string;
5
7
  error: Error;
6
8
  }) => React.JSX.Element;
9
+ export declare const showErrorModal: (title: string, message: string, cms: TinaCMS) => void;
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { useDocumentCreatorPlugin } from './hooks/use-content-creator';
9
9
  export { TinaAdmin } from './admin';
10
10
  export { RouteMappingPlugin } from './admin/plugins/route-mapping';
11
11
  export { TinaAdminApi } from './admin/api';
12
- export { ErrorDialog } from './admin/components/ErrorDialog';
12
+ export { ErrorDialog, showErrorModal } from './admin/components/ErrorDialog';
13
13
  export * from './toolkit';
14
14
  export { Form } from './toolkit/forms/form';
15
15
  export { MdxFieldPluginExtendible } from '@tinacms/toolkit';
package/dist/index.js CHANGED
@@ -7,6 +7,8 @@ import React__default, { useState, useCallback, useRef, useEffect, createContext
7
7
  import { createPortal } from "react-dom";
8
8
  import { clsx } from "clsx";
9
9
  import { twMerge } from "tailwind-merge";
10
+ import { CircleAlert, X, Search, ChevronDown, Check, AlertTriangle, BracesIcon, Heading6 as Heading6$1, Heading5 as Heading5$1, Heading4 as Heading4$1, Heading3 as Heading3$1, Heading2 as Heading2$1, Heading1 as Heading1$1, ChevronRight, Twitter, SunMedium, Moon, SeparatorHorizontal, Eye, Link2Off, Underline, Trash, Text, Table as Table$1, Superscript, Subscript, Strikethrough, Baseline, Highlighter, Settings, RectangleHorizontal, RotateCcw, Pilcrow, Outdent, MoreHorizontal, Minus, WrapText, Keyboard, Indent, ExternalLink, Smile, Edit2, GripVertical, MessageSquarePlus, MessageSquare, Ungroup, Combine, RectangleVertical, FileCode, PaintBucket, ChevronsUpDown, Quote, AlignRight as AlignRight$1, AlignLeft as AlignLeft$1, AlignJustify, AlignCenter as AlignCenter$1, Plus, PaintBucketIcon, CombineIcon, SquareSplitHorizontalIcon, Grid2X2Icon, Trash2Icon, ArrowUp, ArrowDown, XIcon, ArrowLeft, ArrowRight, EraserIcon, Info, CircleCheck as CircleCheck$1, CircleIcon, ChevronDownIcon as ChevronDownIcon$1, File as File$1, ChevronUp, Edit, Pencil, Clock, CalendarCheck, Calendar as Calendar$1, CalendarDays, RotateCw, ChevronLeft, WifiOff, TriangleAlert, RefreshCw, GitBranch, CircleHelp, Loader2, Lock, ArrowUpDown, GitFork, Globe, Copy, Folder as Folder$1, Clapperboard, LayoutGrid, List as List$1, CloudUpload, ArrowDownToLine, TextCursorInput, Images, AlertCircle, Image, Database, CheckCircle2, ImageOff, KeyRound, Cloud, LoaderCircle, ScrollText, RefreshCwOff, OctagonAlert, Menu, FilePlus, LogOut, FileStack, FolderOpen, History, Users, PanelLeft, Files, User, FileText, GitBranchIcon, Circle as Circle$1, ListOrdered, Grid3x3Icon, CircleX, Link, Unlink, SquarePen, Trash2, House, Unlock } from "lucide-react";
11
+ import { isSafeCssColor } from "@tinacms/mdx/sanitize-css-color";
10
12
  import { withRef, cn as cn$1, withCn, createPrimitiveElement, withVariants, withProps, PortalBody, useComposedRef as useComposedRef$1 } from "@udecode/cn";
11
13
  import { BoldPlugin, ItalicPlugin, StrikethroughPlugin, UnderlinePlugin, CodePlugin, BasicMarksPlugin } from "@udecode/plate-basic-marks/react";
12
14
  import { BlockquotePlugin } from "@udecode/plate-block-quote/react";
@@ -18,9 +20,9 @@ import { useLink, LinkPlugin, useLinkToolbarButtonState, useLinkToolbarButton, u
18
20
  import { BulletedListPlugin, NumberedListPlugin, ListItemPlugin, TodoListPlugin, useListToolbarButtonState, useListToolbarButton, ListPlugin } from "@udecode/plate-list/react";
19
21
  import { SlashInputPlugin, SlashPlugin } from "@udecode/plate-slash-command/react";
20
22
  import { TablePlugin, TableRowPlugin, useTableCellElement, TableProvider, useTableElement, useTableMergeState, useTableBordersDropdownMenuContentState, TableCellPlugin, TableCellHeaderPlugin } from "@udecode/plate-table/react";
21
- import { PlateElement, useReadOnly, useElement, PlateLeaf, useSelected, useFocused, useEditorRef, withRef as withRef$1, useComposedRef, useEditorPlugin, useElementSelector, withHOC, usePluginOption, useRemoveNodeButton, useEditorSelector, ParagraphPlugin, createPlatePlugin, PlateContent, PlateContainer, useEditorState, useMarkToolbarButtonState, useMarkToolbarButton, usePlateEditor, useFormInputProps, useEditorSelection, useEditorReadOnly, useOnClickOutside, useEventEditorValue, Plate } from "@udecode/plate/react";
23
+ import { PlateElement, useReadOnly, useElement, PlateLeaf, useSelected, useFocused, useEditorRef, withRef as withRef$1, useComposedRef, useEditorPlugin, useElementSelector, withHOC, usePluginOption, useRemoveNodeButton, useEditorSelector, createPlatePlugin, ParagraphPlugin, PlateContent, PlateContainer, useEditorState, useMarkToolbarButtonState, useMarkToolbarButton, usePlateEditor, useFormInputProps, useEditorSelection, useEditorReadOnly, useOnClickOutside, useEventEditorValue, Plate } from "@udecode/plate/react";
24
+ import colorString, { get as get$1, to } from "color-string";
22
25
  import { isLangSupported, formatCodeBlock, insertEmptyCodeBlock, isCodeBlockEmpty, unwrapCodeBlock, isSelectionAtCodeBlockStart } from "@udecode/plate-code-block";
23
- import { X, Search, ChevronDown, Check, AlertTriangle, BracesIcon, Heading6 as Heading6$1, Heading5 as Heading5$1, Heading4 as Heading4$1, Heading3 as Heading3$1, Heading2 as Heading2$1, Heading1 as Heading1$1, ChevronRight, Twitter, SunMedium, Moon, SeparatorHorizontal, Eye, Link2Off, Underline, Trash, Text, Table as Table$1, Superscript, Subscript, Strikethrough, Highlighter, Settings, RectangleHorizontal, RotateCcw, Pilcrow, Outdent, MoreHorizontal, Minus, WrapText, Keyboard, Indent, ExternalLink, Smile, Edit2, GripVertical, MessageSquarePlus, MessageSquare, Ungroup, Combine, RectangleVertical, Baseline, FileCode, PaintBucket, ChevronsUpDown, Quote, AlignRight as AlignRight$1, AlignLeft as AlignLeft$1, AlignJustify, AlignCenter as AlignCenter$1, Plus, PaintBucketIcon, CombineIcon, SquareSplitHorizontalIcon, Grid2X2Icon, Trash2Icon, ArrowUp, ArrowDown, XIcon, ArrowLeft, ArrowRight, EraserIcon, Info, CircleAlert, CircleCheck as CircleCheck$1, CircleIcon, ChevronDownIcon as ChevronDownIcon$1, File as File$1, ChevronUp, Edit, Pencil, Clock, CalendarCheck, Calendar as Calendar$1, CalendarDays, RotateCw, ChevronLeft, WifiOff, TriangleAlert, RefreshCw, GitBranch, CircleHelp, Loader2, Lock, ArrowUpDown, GitFork, Globe, Copy, Folder as Folder$1, Clapperboard, LayoutGrid, List as List$1, CloudUpload, ArrowDownToLine, TextCursorInput, Images, AlertCircle, Image, Database, CheckCircle2, ImageOff, KeyRound, Cloud, LoaderCircle, ScrollText, RefreshCwOff, OctagonAlert, Menu, FilePlus, LogOut, FileStack, FolderOpen, History, Users, PanelLeft, Files, User, FileText, GitBranchIcon, Circle as Circle$1, ListOrdered, Grid3x3Icon, CircleX, Link, Unlink, SquarePen, Trash2, House, Unlock } from "lucide-react";
24
26
  import { Slot } from "@radix-ui/react-slot";
25
27
  import { cva } from "class-variance-authority";
26
28
  import { Command as Command$2 } from "cmdk";
@@ -32,7 +34,7 @@ import { useHTMLInputCursorState, useComboboxInput } from "@udecode/plate-combob
32
34
  import { useComboboxContext, Combobox as Combobox$1, useComboboxStore, ComboboxProvider, Portal, ComboboxPopover, ComboboxItem } from "@ariakit/react";
33
35
  import { filterWords } from "@udecode/plate-combobox";
34
36
  import { toggleList, unwrapList, getListItemEntry } from "@udecode/plate-list";
35
- import { normalizeHeadingLevels, ALL_HEADING_LEVELS, MEDIA_MIME_TYPES, extensionOf, resolveMediaAccept, ASYNC_POLLER_ERROR, ERR_BRANCH_EXISTS, ERR_BRANCH_CONFLICT, MEDIA_CATEGORIES, canonicalPath, isHeadingLevel, TinaSchema, addNamespaceToSchema, parseURL, ERR_HAS_REFERENCES, ERR_ALREADY_EXISTS, isValidRelativePath, RELATIVE_PATH_ALLOWED_CHARS_MESSAGE, resolveForm, RELATIVE_PATH_REGEX, normalizePath, ERR_NOT_INDEXED, validateSchema } from "@tinacms/schema-tools";
37
+ import { normalizeHeadingLevels, ALL_HEADING_LEVELS, DEFAULT_TEXT_COLORS, MEDIA_MIME_TYPES, extensionOf, resolveMediaAccept, ASYNC_POLLER_ERROR, ERR_BRANCH_EXISTS, ERR_BRANCH_CONFLICT, MEDIA_CATEGORIES, canonicalPath, isHeadingLevel, TinaSchema, addNamespaceToSchema, parseURL, ERR_HAS_REFERENCES, ERR_ALREADY_EXISTS, isValidRelativePath, RELATIVE_PATH_ALLOWED_CHARS_MESSAGE, resolveForm, RELATIVE_PATH_REGEX, normalizePath, ERR_NOT_INDEXED, validateSchema } from "@tinacms/schema-tools";
36
38
  import { NAMER, resolveField } from "@tinacms/schema-tools";
37
39
  import { useBlockSelected, BlockSelectionPlugin } from "@udecode/plate-selection/react";
38
40
  import "@udecode/plate-dnd";
@@ -41,7 +43,6 @@ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
41
43
  import * as ToolbarPrimitive from "@radix-ui/react-toolbar";
42
44
  import * as SeparatorPrimitive from "@radix-ui/react-separator";
43
45
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
44
- import colorString, { get as get$1, to } from "color-string";
45
46
  import { ElementApi, isType, NodeApi, mergeProps, createSlatePlugin } from "@udecode/plate";
46
47
  import { createForm, FORM_ERROR, getIn } from "final-form";
47
48
  import arrayMutators from "final-form-arrays";
@@ -851,6 +852,12 @@ const PopupModal = ({ className = "", style = {}, ...props }) => /* @__PURE__ */
851
852
  }
852
853
  );
853
854
  const ModalPopup = PopupModal;
855
+ const ErrorModal = ({
856
+ title,
857
+ actions,
858
+ close: close2,
859
+ children
860
+ }) => /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, { close: close2 }, /* @__PURE__ */ React__default.createElement(CircleAlert, { className: "mr-1 w-6 h-auto inline-block text-red-600" }), " ", title), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose whitespace-pre-wrap" }, children)), /* @__PURE__ */ React__default.createElement(ModalActions, { align: "end" }, actions)));
854
861
  const ERROR_MISSING_CMS = `useCMS could not find an instance of CMS`;
855
862
  const CMSContext = React.createContext(null);
856
863
  function useCMS$1() {
@@ -2000,6 +2007,7 @@ const Icons = {
2000
2007
  search: Search,
2001
2008
  settings: Settings,
2002
2009
  highlight: Highlighter,
2010
+ textColor: Baseline,
2003
2011
  strikethrough: Strikethrough,
2004
2012
  subscript: Subscript,
2005
2013
  superscript: Superscript,
@@ -2596,18 +2604,33 @@ const InlineComboboxEmpty = ({
2596
2604
  const ToolbarContext = createContext(
2597
2605
  void 0
2598
2606
  );
2607
+ const resolvePalette = (configured, fallback) => {
2608
+ if (!configured) return fallback;
2609
+ return configured.filter(({ value }) => {
2610
+ if (isSafeCssColor(value)) return true;
2611
+ console.warn(
2612
+ `[tinacms] Ignoring unsupported colour "${value}" in rich-text overrides.textColors. Use hex, a named colour, a colour function such as rgb()/lab()/color-mix(), or var(--name).`
2613
+ );
2614
+ return false;
2615
+ });
2616
+ };
2599
2617
  const ToolbarProvider = ({
2600
2618
  tinaForm,
2601
2619
  templates,
2602
2620
  overrides,
2603
2621
  children
2604
2622
  }) => {
2605
- const configured = !Array.isArray(overrides) ? overrides == null ? void 0 : overrides.headingLevels : void 0;
2623
+ const objectOverrides = !Array.isArray(overrides) ? overrides : void 0;
2624
+ const configured = objectOverrides == null ? void 0 : objectOverrides.headingLevels;
2606
2625
  const headingLevelsConfigured = Array.isArray(configured);
2607
2626
  const headingLevels = useMemo(
2608
2627
  () => configured ? normalizeHeadingLevels(configured) : ALL_HEADING_LEVELS,
2609
2628
  [configured]
2610
2629
  );
2630
+ const textColors = useMemo(
2631
+ () => resolvePalette(objectOverrides == null ? void 0 : objectOverrides.textColors, DEFAULT_TEXT_COLORS),
2632
+ [objectOverrides == null ? void 0 : objectOverrides.textColors]
2633
+ );
2611
2634
  return /* @__PURE__ */ React__default.createElement(
2612
2635
  ToolbarContext.Provider,
2613
2636
  {
@@ -2616,7 +2639,8 @@ const ToolbarProvider = ({
2616
2639
  templates,
2617
2640
  overrides,
2618
2641
  headingLevels,
2619
- headingLevelsConfigured
2642
+ headingLevelsConfigured,
2643
+ textColors
2620
2644
  }
2621
2645
  },
2622
2646
  children
@@ -3309,6 +3333,10 @@ const TableRowElement = withRef(
3309
3333
  );
3310
3334
  }
3311
3335
  );
3336
+ const TextColorPlugin = createPlatePlugin({
3337
+ key: "textColor",
3338
+ node: { isLeaf: true }
3339
+ });
3312
3340
  function classNames$1(...classes) {
3313
3341
  return classes.filter(Boolean).join(" ");
3314
3342
  }
@@ -3327,22 +3355,38 @@ function getContrastColor(color) {
3327
3355
  const luminance = (0.299 * r2 + 0.587 * g + 0.114 * b) / 255;
3328
3356
  return luminance > 0.5 ? "#000000" : "#ffffff";
3329
3357
  }
3358
+ const leafColor = (value) => typeof value === "string" && isSafeCssColor(value) ? value : void 0;
3359
+ const INHERIT_NESTED_COLOR = "[&_strong]:text-inherit [&_em]:text-inherit [&_s]:text-inherit [&_u]:text-inherit";
3330
3360
  const HighlightLeaf = ({
3331
3361
  leaf: leaf2,
3332
3362
  ...props
3333
3363
  }) => {
3334
- const backgroundColor = leaf2.highlightColor || "#FEF08A";
3364
+ const backgroundColor = leafColor(leaf2.highlightColor) ?? "#FEF08A";
3365
+ const color = leafColor(leaf2.textColor) ?? getContrastColor(backgroundColor);
3335
3366
  return /* @__PURE__ */ React__default.createElement(
3336
3367
  PlateLeaf,
3337
3368
  {
3338
3369
  as: "mark",
3339
- className: "rounded-sm",
3340
- style: { backgroundColor, color: getContrastColor(backgroundColor) },
3370
+ className: `rounded-sm ${INHERIT_NESTED_COLOR}`,
3371
+ style: { backgroundColor, color },
3341
3372
  leaf: leaf2,
3342
3373
  ...props
3343
3374
  }
3344
3375
  );
3345
3376
  };
3377
+ const TextColorLeaf = ({
3378
+ leaf: leaf2,
3379
+ ...props
3380
+ }) => /* @__PURE__ */ React__default.createElement(
3381
+ PlateLeaf,
3382
+ {
3383
+ as: "span",
3384
+ className: INHERIT_NESTED_COLOR,
3385
+ style: { color: leafColor(leaf2.textColor) },
3386
+ leaf: leaf2,
3387
+ ...props
3388
+ }
3389
+ );
3346
3390
  const Heading1 = ({
3347
3391
  attributes,
3348
3392
  children,
@@ -3499,6 +3543,7 @@ const Components = () => {
3499
3543
  [LinkPlugin.key]: LinkElement,
3500
3544
  [CodePlugin.key]: CodeLeaf,
3501
3545
  [HighlightPlugin.key]: HighlightLeaf,
3546
+ [TextColorPlugin.key]: TextColorLeaf,
3502
3547
  [UnderlinePlugin.key]: withProps(PlateLeaf, { as: "u" }),
3503
3548
  [StrikethroughPlugin.key]: withProps(PlateLeaf, { as: "s" }),
3504
3549
  [ItalicPlugin.key]: withProps(PlateLeaf, { as: "em" }),
@@ -3788,7 +3833,20 @@ class Form {
3788
3833
  if (field.templates) {
3789
3834
  if (field.list) {
3790
3835
  if (isLastItem) {
3791
- return formOrObjectField;
3836
+ const fieldName = namePath.slice(0, namePathIndex).join(".");
3837
+ if (!fieldName) {
3838
+ return formOrObjectField;
3839
+ }
3840
+ return {
3841
+ ...formOrObjectField,
3842
+ name: fieldName,
3843
+ fields: formOrObjectField.fields.map((field2) => {
3844
+ return {
3845
+ ...field2,
3846
+ name: [fieldName, field2.name].join(".")
3847
+ };
3848
+ })
3849
+ };
3792
3850
  } else {
3793
3851
  const namePathIndexForListItem = namePathIndex + 1;
3794
3852
  const index = namePath[namePathIndexForListItem];
@@ -6287,7 +6345,7 @@ const ListFieldMeta = ({
6287
6345
  style: { zIndex: index != null ? 1e3 - index : void 0 },
6288
6346
  ...props
6289
6347
  },
6290
- /* @__PURE__ */ React.createElement(ListHeader, null, /* @__PURE__ */ React.createElement(ListMeta, null, label !== false && /* @__PURE__ */ React.createElement(ListLabel, null, label || name2), description && /* @__PURE__ */ React.createElement(FieldDescription, { className: "whitespace-nowrap text-ellipsis overflow-hidden" }, description)), actions && actions),
6348
+ /* @__PURE__ */ React.createElement(ListHeader, null, /* @__PURE__ */ React.createElement(ListMeta, null, label !== false && /* @__PURE__ */ React.createElement(ListLabel, null, label || name2), description && /* @__PURE__ */ React.createElement(FieldDescription, null, description)), actions && actions),
6291
6349
  children,
6292
6350
  error && typeof error === "string" && /* @__PURE__ */ React.createElement(FieldError, null, error)
6293
6351
  );
@@ -6296,7 +6354,7 @@ const ListHeader = ({ children }) => {
6296
6354
  return /* @__PURE__ */ React.createElement("span", { className: "relative flex gap-2 w-full justify-between items-center mb-2" }, children);
6297
6355
  };
6298
6356
  const ListMeta = ({ children }) => {
6299
- return /* @__PURE__ */ React.createElement("div", { className: "flex-1 truncate" }, children);
6357
+ return /* @__PURE__ */ React.createElement("div", { className: "flex-1 min-w-0" }, children);
6300
6358
  };
6301
6359
  const ListLabel = ({ children }) => {
6302
6360
  return /* @__PURE__ */ React.createElement(
@@ -7533,8 +7591,8 @@ const ImageField = wrapFieldsWithMeta(
7533
7591
  `${fileRejection.file.name}: ${fileRejection.errors.map((error) => printError(error)).join(", ")}`
7534
7592
  );
7535
7593
  });
7536
- cms.alerts.error(() => {
7537
- return /* @__PURE__ */ React.createElement(React.Fragment, null, "Upload Failed. ", /* @__PURE__ */ React.createElement("br", null), messages.join(". "), ".");
7594
+ cms.alerts.error(`${messages.join(". ")}.`, {
7595
+ title: "Upload Failed"
7538
7596
  });
7539
7597
  }
7540
7598
  } catch (error) {
@@ -7789,6 +7847,10 @@ const TagsFieldPlugin = {
7789
7847
  };
7790
7848
  const DEFAULT_DATE_DISPLAY_FORMAT = "MMM DD, YYYY";
7791
7849
  const DEFAULT_TIME_DISPLAY_FORMAT = "h:mm A";
7850
+ const getHourCycle = (timeFormat) => {
7851
+ const tokens = (timeFormat ?? "").replace(/\[[^\]]*\]/g, "");
7852
+ return /[Hk]/.test(tokens) ? 24 : 12;
7853
+ };
7792
7854
  const format$2 = (val, _name, field) => {
7793
7855
  if (!val) return val;
7794
7856
  return new Date(val).toISOString();
@@ -8704,7 +8766,7 @@ const DateField = wrapFieldsWithMeta(
8704
8766
  value ? value.toISOString() : required !== false ? (/* @__PURE__ */ new Date()).toISOString() : value
8705
8767
  ),
8706
8768
  timeFormat: getTimeFormat(),
8707
- hourCycle: 12,
8769
+ hourCycle: getHourCycle(getTimeFormat()),
8708
8770
  dateFormat: getDateFormat(),
8709
8771
  value: date,
8710
8772
  locale: rest.locale ? { code: rest.locale } : void 0
@@ -10108,7 +10170,7 @@ let Alerts$1 = class Alerts {
10108
10170
  ...eventsToAlerts
10109
10171
  };
10110
10172
  }
10111
- add(level, message, timeout = 4e3) {
10173
+ add(level, message, timeout = 4e3, title) {
10112
10174
  if (this.suppressed) {
10113
10175
  return () => {
10114
10176
  };
@@ -10117,6 +10179,7 @@ let Alerts$1 = class Alerts {
10117
10179
  level,
10118
10180
  message,
10119
10181
  timeout,
10182
+ title,
10120
10183
  id: `${message}|${Date.now()}`
10121
10184
  };
10122
10185
  this.alerts.set(alert.id, alert);
@@ -10149,8 +10212,11 @@ let Alerts$1 = class Alerts {
10149
10212
  warn(message, timeout) {
10150
10213
  return this.add("warn", message, timeout);
10151
10214
  }
10152
- error(message, timeout) {
10153
- return this.add("error", message, timeout);
10215
+ error(message, options) {
10216
+ if (typeof options === "number") {
10217
+ return this.add("error", message, options);
10218
+ }
10219
+ return this.add("error", message, void 0, options == null ? void 0 : options.title);
10154
10220
  }
10155
10221
  };
10156
10222
  class EventBus {
@@ -12480,8 +12546,8 @@ function MediaPicker({
12480
12546
  `${fileRejection.file.name}: ${fileRejection.errors.map((error) => printError(error)).join(", ")}`
12481
12547
  );
12482
12548
  });
12483
- cms.alerts.error(() => {
12484
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "Upload Failed. ", /* @__PURE__ */ React__default.createElement("br", null), messages.join(". "), ".");
12549
+ cms.alerts.error(`${messages.join(". ")}.`, {
12550
+ title: "Upload Failed"
12485
12551
  });
12486
12552
  }
12487
12553
  if (mediaItems.length !== 0) {
@@ -14305,7 +14371,7 @@ const FormModal = ({ plugin, close: close2 }) => {
14305
14371
  const name = "tinacms";
14306
14372
  const type = "module";
14307
14373
  const typings = "dist/index.d.ts";
14308
- const version = "3.14.3";
14374
+ const version = "3.15.0";
14309
14375
  const main = "dist/index.js";
14310
14376
  const module$1 = "./dist/index.js";
14311
14377
  const exports$1 = { ".": "./dist/index.js", "./dist/client": { "types": "./dist/client.d.ts", "browser": "./dist/client.browser.js", "default": "./dist/client.js" }, "./react": "./dist/react.js", "./dist/react": "./dist/react.js", "./tina-field": "./dist/tina-field.js", "./dist/tina-field": "./dist/tina-field.js", "./dist/rich-text": "./dist/rich-text/index.js", "./dist/rich-text/static": "./dist/rich-text/static.js", "./dist/rich-text/prism": "./dist/rich-text/prism.js" };
@@ -14314,7 +14380,7 @@ const buildConfig = { "entryPoints": ["src/index.ts", "src/rich-text/index.tsx",
14314
14380
  const license = "Apache-2.0";
14315
14381
  const scripts = { "types": "pnpm tsc && pnpm tsc-alias", "build": "tinacms-scripts build", "test": "vitest run", "test-watch": "vitest" };
14316
14382
  const dependencies = { "@ariakit/react": "catalog:", "@dnd-kit/core": "catalog:", "@dnd-kit/sortable": "catalog:", "@dnd-kit/utilities": "catalog:", "@floating-ui/dom": "catalog:", "@floating-ui/react-dom": "catalog:", "@graphql-inspector/core": "^6.2.1", "@radix-ui/react-dialog": "catalog:", "@radix-ui/react-dropdown-menu": "catalog:", "@radix-ui/react-popover": "catalog:", "@radix-ui/react-select": "catalog:", "@radix-ui/react-separator": "catalog:", "@radix-ui/react-slot": "catalog:", "@radix-ui/react-toolbar": "catalog:", "@radix-ui/react-tooltip": "catalog:", "@react-hook/window-size": "catalog:", "@tanstack/react-table": "^8.21.3", "@tinacms/bridge": "workspace:^", "@tinacms/mdx": "workspace:^", "@tinacms/schema-tools": "workspace:^", "@tinacms/search": "workspace:^", "@udecode/cmdk": "catalog:", "@udecode/cn": "catalog:", "@udecode/plate": "catalog:", "@udecode/plate-autoformat": "catalog:", "@udecode/plate-basic-marks": "catalog:", "@udecode/plate-block-quote": "catalog:", "@udecode/plate-break": "catalog:", "@udecode/plate-code-block": "catalog:", "@udecode/plate-combobox": "catalog:", "@udecode/plate-dnd": "catalog:", "@udecode/plate-floating": "catalog:", "@udecode/plate-heading": "catalog:", "@udecode/plate-highlight": "catalog:", "@udecode/plate-horizontal-rule": "catalog:", "@udecode/plate-indent-list": "catalog:", "@udecode/plate-link": "catalog:", "@udecode/plate-list": "catalog:", "@udecode/plate-node-id": "catalog:", "@udecode/plate-reset-node": "catalog:", "@udecode/plate-resizable": "catalog:", "@udecode/plate-selection": "catalog:", "@udecode/plate-slash-command": "catalog:", "@udecode/plate-table": "catalog:", "@udecode/plate-trailing-block": "catalog:", "class-variance-authority": "catalog:", "clsx": "catalog:", "cmdk": "catalog:", "color-string": "catalog:", "date-fns": "4.1.0", "es-toolkit": "^1.42.0", "final-form": "catalog:", "final-form-arrays": "catalog:", "final-form-set-field-data": "catalog:", "graphql": "15.8.0", "graphql-tag": "catalog:", "is-hotkey": "catalog:", "lucide-react": "catalog:", "mermaid": "catalog:", "posthog-js": "^1.347.1", "prism-react-renderer": "catalog:", "prop-types": "catalog:", "react-colorful": "catalog:", "react-day-picker": "^9.13.0", "react-dnd": "catalog:", "react-dnd-html5-backend": "catalog:", "react-dropzone": "catalog:", "react-final-form": "catalog:", "react-router-dom": "catalog:", "react-use": "catalog:", "tailwind-merge": "^2.6.0", "webfontloader": "catalog:", "yup": "^1.6.1", "zod": "catalog:" };
14317
- const devDependencies = { "@graphql-tools/utils": "catalog:", "@testing-library/dom": "catalog:", "@testing-library/jest-dom": "catalog:", "@testing-library/react": "catalog:", "@testing-library/user-event": "catalog:", "@tinacms/scripts": "workspace:*", "@types/atob": "catalog:", "@types/codemirror": "catalog:", "@types/color-string": "catalog:", "@types/node": "^22.13.1", "@types/prop-types": "catalog:", "@types/react": "^18.3.18", "@types/react-dom": "catalog:", "happy-dom": "catalog:", "identity-obj-proxy": "catalog:", "jest-file-snapshot": "^0.7.0", "lowlight": "catalog:", "next": "15.5.21", "react": "^18.3.1", "react-dom": "^18.3.1", "react-is": "^18.3.1", "tsc-alias": "catalog:", "tslib": "catalog:", "typescript": "^5.7.3", "vite": "^5.4.14", "vitest": "^2.1.9" };
14383
+ const devDependencies = { "@testing-library/dom": "catalog:", "@testing-library/jest-dom": "catalog:", "@testing-library/react": "catalog:", "@testing-library/user-event": "catalog:", "@tinacms/scripts": "workspace:*", "@types/atob": "catalog:", "@types/codemirror": "catalog:", "@types/color-string": "catalog:", "@types/node": "^22.13.1", "@types/prop-types": "catalog:", "@types/react": "^18.3.18", "@types/react-dom": "catalog:", "happy-dom": "catalog:", "identity-obj-proxy": "catalog:", "jest-file-snapshot": "^0.7.0", "lowlight": "catalog:", "next": "15.5.27", "react": "^18.3.1", "react-dom": "^18.3.1", "react-is": "^18.3.1", "tsc-alias": "catalog:", "tslib": "catalog:", "typescript": "^5.7.3", "vite": "^5.4.14", "vitest": "^2.1.9" };
14318
14384
  const peerDependencies = { "react": ">=16.14.0", "react-dom": ">=16.14.0" };
14319
14385
  const publishConfig = { "registry": "https://registry.npmjs.org" };
14320
14386
  const repository = { "url": "https://github.com/tinacms/tinacms.git", "directory": "packages/tinacms" };
@@ -16615,26 +16681,19 @@ function Alerts2({ alerts }) {
16615
16681
  const AlertMessage = typeof alert.message === "string" ? () => {
16616
16682
  return /* @__PURE__ */ React__default.createElement("p", { className: "text-base mb-3 overflow-y-auto" }, parseUrlsInText(alert.message.toString()));
16617
16683
  } : alert.message;
16618
- return /* @__PURE__ */ React__default.createElement(Modal, { key: alert.id }, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(
16619
- ModalHeader,
16684
+ const dismiss = () => {
16685
+ alerts.dismiss(alert);
16686
+ };
16687
+ return /* @__PURE__ */ React__default.createElement(
16688
+ ErrorModal,
16620
16689
  {
16621
- close: () => {
16622
- alerts.dismiss(alert);
16623
- }
16690
+ key: alert.id,
16691
+ title: alert.title ?? "Error",
16692
+ close: dismiss,
16693
+ actions: /* @__PURE__ */ React__default.createElement(Button$2, { className: "w-full sm:w-auto", onClick: dismiss }, "Close")
16624
16694
  },
16625
- /* @__PURE__ */ React__default.createElement(CircleAlert, { className: "mr-1 w-6 h-auto inline-block text-red-600" }),
16626
- " ",
16627
- "Error"
16628
- ), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose whitespace-pre-wrap" }, /* @__PURE__ */ React__default.createElement(AlertMessage, null))), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex-1" }), /* @__PURE__ */ React__default.createElement(
16629
- Button$2,
16630
- {
16631
- style: { flexGrow: 1 },
16632
- onClick: () => {
16633
- alerts.dismiss(alert);
16634
- }
16635
- },
16636
- "Close"
16637
- ))));
16695
+ /* @__PURE__ */ React__default.createElement(AlertMessage, null)
16696
+ );
16638
16697
  }));
16639
16698
  }
16640
16699
  const Alert = ({
@@ -18359,7 +18418,16 @@ const FormBuilder = ({
18359
18418
  };
18360
18419
  const FormStatus = ({ pristine }) => {
18361
18420
  const pristineClass = pristine ? "text-green-500" : "text-red-500";
18362
- return /* @__PURE__ */ React.createElement(Circle$1, { className: cn("w-3 h-3 fill-current", pristineClass) });
18421
+ const label = pristine ? "No unsaved changes" : "Unsaved changes";
18422
+ return /* @__PURE__ */ React.createElement(
18423
+ Circle$1,
18424
+ {
18425
+ role: "img",
18426
+ "aria-label": label,
18427
+ className: cn("w-3 h-3 fill-current", pristineClass)
18428
+ },
18429
+ /* @__PURE__ */ React.createElement("title", null, label)
18430
+ );
18363
18431
  };
18364
18432
  const RelatedFilesBanner = () => {
18365
18433
  const cms = useCMS$1();
@@ -19652,18 +19720,11 @@ const MarkToolbarButton = withRef(({ clear, nodeType, ...rest }, ref) => {
19652
19720
  const { props } = useMarkToolbarButton(state);
19653
19721
  return /* @__PURE__ */ React__default.createElement(ToolbarButton, { ref, ...props, ...rest });
19654
19722
  });
19655
- const highlightColors = [
19656
- { label: "Yellow", value: "#FEF08A" },
19657
- { label: "Green", value: "#BBF7D0" },
19658
- { label: "Blue", value: "#BFDBFE" },
19659
- { label: "Red", value: "#CC4141" }
19660
- ];
19661
19723
  const BoldToolbarButton = () => /* @__PURE__ */ React__default.createElement(MarkToolbarButton, { tooltip: "Bold (⌘+B)", nodeType: BoldPlugin.key }, /* @__PURE__ */ React__default.createElement(Icons.bold, null));
19662
19724
  const StrikethroughToolbarButton = () => /* @__PURE__ */ React__default.createElement(MarkToolbarButton, { tooltip: "Strikethrough", nodeType: StrikethroughPlugin.key }, /* @__PURE__ */ React__default.createElement(Icons.strikethrough, null));
19663
19725
  const ItalicToolbarButton = () => /* @__PURE__ */ React__default.createElement(MarkToolbarButton, { tooltip: "Italic (⌘+I)", nodeType: ItalicPlugin.key }, /* @__PURE__ */ React__default.createElement(Icons.italic, null));
19664
19726
  const CodeToolbarButton = () => /* @__PURE__ */ React__default.createElement(MarkToolbarButton, { tooltip: "Code (⌘+E)", nodeType: CodePlugin.key }, /* @__PURE__ */ React__default.createElement(Icons.code, null));
19665
- const HighlightToolbarButton = () => /* @__PURE__ */ React__default.createElement(HighlightColorToolbarButton, null);
19666
- const useHighlightToolbar = () => {
19727
+ const useColorMarkToolbar = (toMarks) => {
19667
19728
  const editor = useEditorRef();
19668
19729
  const openState = useOpenState();
19669
19730
  const savedSelection = React__default.useRef(editor.selection);
@@ -19680,8 +19741,8 @@ const useHighlightToolbar = () => {
19680
19741
  rememberSelection();
19681
19742
  }
19682
19743
  }, [openState.open, rememberSelection]);
19683
- const applyHighlight = React__default.useCallback(
19684
- (highlightColor) => {
19744
+ const applyColor = React__default.useCallback(
19745
+ (color) => {
19685
19746
  if (inlineCodeActive) {
19686
19747
  openState.onOpenChange(false);
19687
19748
  return;
@@ -19689,67 +19750,109 @@ const useHighlightToolbar = () => {
19689
19750
  if (savedSelection.current) {
19690
19751
  editor.tf.select(structuredClone(savedSelection.current));
19691
19752
  }
19692
- if (highlightColor) {
19693
- editor.tf.addMark("highlight", true);
19694
- editor.tf.addMark("highlightColor", highlightColor);
19695
- } else {
19696
- editor.tf.removeMark("highlight");
19697
- editor.tf.removeMark("highlightColor");
19698
- }
19699
- editor.tf.setNodes(
19700
- highlightColor ? {
19701
- highlight: true,
19702
- highlightColor
19703
- } : {
19704
- highlight: void 0,
19705
- highlightColor: void 0
19706
- },
19707
- {
19708
- at: editor.selection ?? void 0,
19709
- match: (node) => editor.api.isText(node),
19710
- split: true
19753
+ const marks = toMarks(color);
19754
+ for (const [key, value] of Object.entries(marks)) {
19755
+ if (value === void 0) {
19756
+ editor.tf.removeMark(key);
19757
+ } else {
19758
+ editor.tf.addMark(key, value);
19711
19759
  }
19712
- );
19760
+ }
19761
+ editor.tf.setNodes(marks, {
19762
+ at: editor.selection ?? void 0,
19763
+ match: (node) => editor.api.isText(node),
19764
+ split: true
19765
+ });
19713
19766
  editor.tf.focus();
19714
19767
  openState.onOpenChange(false);
19715
19768
  },
19716
- [editor, inlineCodeActive, openState]
19769
+ [editor, inlineCodeActive, openState, toMarks]
19717
19770
  );
19718
19771
  return {
19719
- applyHighlight,
19772
+ applyColor,
19720
19773
  inlineCodeActive,
19721
19774
  openState,
19722
19775
  rememberSelection
19723
19776
  };
19724
19777
  };
19725
- const HighlightColorToolbarButton = () => {
19726
- const { applyHighlight, inlineCodeActive, openState, rememberSelection } = useHighlightToolbar();
19778
+ const ColorDropdownToolbarButton = ({
19779
+ tooltip,
19780
+ icon,
19781
+ clearLabel,
19782
+ colors,
19783
+ toMarks,
19784
+ renderSwatch
19785
+ }) => {
19786
+ const { applyColor, inlineCodeActive, openState, rememberSelection } = useColorMarkToolbar(toMarks);
19727
19787
  return /* @__PURE__ */ React__default.createElement(DropdownMenu$1, { modal: false, ...openState }, /* @__PURE__ */ React__default.createElement(DropdownMenuTrigger$1, { asChild: true }, /* @__PURE__ */ React__default.createElement(
19728
19788
  ToolbarButton,
19729
19789
  {
19730
19790
  isDropdown: true,
19731
19791
  showArrow: true,
19732
19792
  pressed: openState.open,
19733
- tooltip: "Highlight color",
19793
+ tooltip,
19734
19794
  disabled: inlineCodeActive,
19735
19795
  onMouseDown: rememberSelection
19736
19796
  },
19737
- /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React__default.createElement(Icons.highlight, null), /* @__PURE__ */ React__default.createElement("span", { className: "sr-only" }, "Highlight color"))
19738
- )), /* @__PURE__ */ React__default.createElement(DropdownMenuContent$1, { align: "start", className: "min-w-[180px]" }, /* @__PURE__ */ React__default.createElement(DropdownMenuItem$1, { onSelect: () => applyHighlight() }, "Clear highlight"), highlightColors.map((color) => /* @__PURE__ */ React__default.createElement(
19797
+ /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center gap-1.5" }, icon, /* @__PURE__ */ React__default.createElement("span", { className: "sr-only" }, tooltip))
19798
+ )), /* @__PURE__ */ React__default.createElement(DropdownMenuContent$1, { align: "start", className: "min-w-[180px]" }, /* @__PURE__ */ React__default.createElement(DropdownMenuItem$1, { onSelect: () => applyColor() }, clearLabel), colors.map((color) => /* @__PURE__ */ React__default.createElement(
19739
19799
  DropdownMenuItem$1,
19740
19800
  {
19741
19801
  key: color.value,
19742
- onSelect: () => applyHighlight(color.value)
19802
+ onSelect: () => applyColor(color.value)
19743
19803
  },
19744
- /* @__PURE__ */ React__default.createElement(
19804
+ renderSwatch(color.value),
19805
+ color.label
19806
+ ))));
19807
+ };
19808
+ const toHighlightMarks = (color) => color ? { highlight: true, highlightColor: color } : { highlight: void 0, highlightColor: void 0 };
19809
+ const toTextColorMarks = (color) => ({
19810
+ textColor: color
19811
+ });
19812
+ const highlightColors = [
19813
+ { label: "Yellow", value: "#FEF08A" },
19814
+ { label: "Green", value: "#BBF7D0" },
19815
+ { label: "Blue", value: "#BFDBFE" },
19816
+ { label: "Red", value: "#CC4141" }
19817
+ ];
19818
+ const HighlightToolbarButton = () => /* @__PURE__ */ React__default.createElement(
19819
+ ColorDropdownToolbarButton,
19820
+ {
19821
+ tooltip: "Highlight color",
19822
+ icon: /* @__PURE__ */ React__default.createElement(Icons.highlight, null),
19823
+ clearLabel: "Clear highlight",
19824
+ colors: highlightColors,
19825
+ toMarks: toHighlightMarks,
19826
+ renderSwatch: (color) => /* @__PURE__ */ React__default.createElement(
19745
19827
  "span",
19746
19828
  {
19747
19829
  className: "mr-2 inline-block size-4 rounded border border-gray-300",
19748
- style: { backgroundColor: color.value }
19830
+ style: { backgroundColor: color }
19749
19831
  }
19750
- ),
19751
- color.label
19752
- ))));
19832
+ )
19833
+ }
19834
+ );
19835
+ const TextColorToolbarButton = () => {
19836
+ const { textColors } = useToolbarContext();
19837
+ return /* @__PURE__ */ React__default.createElement(
19838
+ ColorDropdownToolbarButton,
19839
+ {
19840
+ tooltip: "Text color",
19841
+ icon: /* @__PURE__ */ React__default.createElement(Icons.textColor, null),
19842
+ clearLabel: "Clear text color",
19843
+ colors: textColors,
19844
+ toMarks: toTextColorMarks,
19845
+ renderSwatch: (color) => /* @__PURE__ */ React__default.createElement(
19846
+ "span",
19847
+ {
19848
+ "aria-hidden": true,
19849
+ className: "mr-2 inline-block w-4 text-center font-bold",
19850
+ style: { color }
19851
+ },
19852
+ "A"
19853
+ )
19854
+ }
19855
+ );
19753
19856
  };
19754
19857
  const ListToolbarButton = withRef(({ nodeType = BulletedListPlugin.key, ...rest }, ref) => {
19755
19858
  const state = useListToolbarButtonState({ nodeType });
@@ -19989,6 +20092,11 @@ const toolbarItems = {
19989
20092
  width: () => STANDARD_ICON_WIDTH,
19990
20093
  Component: /* @__PURE__ */ React__default.createElement(HighlightToolbarButton, null)
19991
20094
  },
20095
+ textColor: {
20096
+ label: "Text Color",
20097
+ width: () => STANDARD_ICON_WIDTH,
20098
+ Component: /* @__PURE__ */ React__default.createElement(TextColorToolbarButton, null)
20099
+ },
19992
20100
  italic: {
19993
20101
  label: "Italic",
19994
20102
  width: () => STANDARD_ICON_WIDTH,
@@ -71389,6 +71497,7 @@ const viewPlugins = [
71389
71497
  BasicMarksPlugin,
71390
71498
  UnderlinePlugin,
71391
71499
  HighlightPlugin,
71500
+ TextColorPlugin,
71392
71501
  HeadingPlugin.configure({ options: { levels: 6 } }),
71393
71502
  ParagraphPlugin,
71394
71503
  CodeBlockPlugin.configure({
@@ -71399,24 +71508,24 @@ const viewPlugins = [
71399
71508
  const CorrectNodeBehaviorPlugin = createSlatePlugin({
71400
71509
  key: "WITH_CORRECT_NODE_BEHAVIOR"
71401
71510
  });
71402
- const ClearHighlightOnEnterPlugin = createSlatePlugin({
71403
- key: "CLEAR_HIGHLIGHT_ON_ENTER"
71511
+ const COLOR_MARK_KEYS = ["highlight", "highlightColor", "textColor"];
71512
+ const ClearColorMarksOnEnterPlugin = createSlatePlugin({
71513
+ key: "CLEAR_COLOR_MARKS_ON_ENTER"
71404
71514
  }).overrideEditor(({ editor, tf: { insertBreak } }) => ({
71405
71515
  transforms: {
71406
71516
  insertBreak() {
71407
71517
  const keyboardEvent = editor.currentKeyboardEvent;
71408
71518
  const isPlainEnter = (keyboardEvent == null ? void 0 : keyboardEvent.key) === "Enter" && !keyboardEvent.shiftKey && !keyboardEvent.metaKey && !keyboardEvent.ctrlKey && !keyboardEvent.altKey;
71409
71519
  const activeMarks = editor.api.marks();
71410
- const hasHighlight = Boolean(
71411
- (activeMarks == null ? void 0 : activeMarks.highlight) || (activeMarks == null ? void 0 : activeMarks.highlightColor)
71520
+ const hasColorMark = COLOR_MARK_KEYS.some(
71521
+ (key) => Boolean(activeMarks == null ? void 0 : activeMarks[key])
71412
71522
  );
71413
71523
  insertBreak();
71414
- if (!isPlainEnter || !hasHighlight) {
71524
+ if (!isPlainEnter || !hasColorMark || !editor.api.isEmpty(editor.selection, { block: true })) {
71415
71525
  return;
71416
71526
  }
71417
- editor.tf.removeMark("highlight");
71418
- editor.tf.removeMark("highlightColor");
71419
- editor.tf.unsetNodes(["highlight", "highlightColor"], {
71527
+ editor.tf.removeMarks(COLOR_MARK_KEYS);
71528
+ editor.tf.unsetNodes(COLOR_MARK_KEYS, {
71420
71529
  at: editor.selection ?? void 0,
71421
71530
  match: (node) => editor.api.isText(node)
71422
71531
  });
@@ -71434,7 +71543,6 @@ const createEditorPlugins = ({
71434
71543
  createHardBreakPlugin,
71435
71544
  createInvalidMarkdownPlugin,
71436
71545
  CorrectNodeBehaviorPlugin,
71437
- ClearHighlightOnEnterPlugin,
71438
71546
  LinkPlugin.configure({
71439
71547
  options: {
71440
71548
  // Custom validation function to allow relative links, e.g., /about
@@ -71542,7 +71650,9 @@ const createEditorPlugins = ({
71542
71650
  }
71543
71651
  ]
71544
71652
  }
71545
- })
71653
+ }),
71654
+ // Last, so it wraps list and other block handlers that don't pass Enter on
71655
+ ClearColorMarksOnEnterPlugin
71546
71656
  ];
71547
71657
  const RichEditor = ({ input, tinaForm, field }) => {
71548
71658
  var _a, _b;
@@ -72511,9 +72621,9 @@ mutation addPendingDocumentMutation(
72511
72621
  throw new SessionExpiredError();
72512
72622
  }
72513
72623
  if (res.status !== 200) {
72514
- let errorMessage = `Unable to complete request, ${res.statusText}`;
72515
- const resBody = await res.json();
72516
- if (resBody.message) {
72624
+ let errorMessage = `Unable to complete request, ${res.statusText || res.status}`;
72625
+ const resBody = await res.json().catch(() => void 0);
72626
+ if (resBody == null ? void 0 : resBody.message) {
72517
72627
  errorMessage = `${errorMessage}, Response: ${resBody.message}`;
72518
72628
  }
72519
72629
  if (!this.isCustomContentApi) {
@@ -72597,7 +72707,7 @@ mutation addPendingDocumentMutation(
72597
72707
  }
72598
72708
  });
72599
72709
  if (!res.ok) {
72600
- let errorMessage = `There was an error creating a pull request. ${res.statusText}`;
72710
+ let errorMessage = `There was an error creating a pull request. ${res.statusText || res.status}`;
72601
72711
  if (res.status === 422) {
72602
72712
  errorMessage = `Please make sure you have made changes on ${branch} before creating a pull request.`;
72603
72713
  }
@@ -72780,8 +72890,10 @@ mutation addPendingDocumentMutation(
72780
72890
  });
72781
72891
  if (!res.ok) {
72782
72892
  console.error("There was an error creating a new branch.");
72783
- const error = await res.json();
72784
- throw new Error(error == null ? void 0 : error.message);
72893
+ const error = await res.json().catch(() => void 0);
72894
+ throw new Error(
72895
+ (error == null ? void 0 : error.message) ?? `Unable to create branch, ${res.statusText || res.status}`
72896
+ );
72785
72897
  }
72786
72898
  const values = await res.json();
72787
72899
  return parseRefForBranchName(values.data.ref);
@@ -72797,7 +72909,9 @@ mutation addPendingDocumentMutation(
72797
72909
  method: "GET"
72798
72910
  });
72799
72911
  if (!res.ok) {
72800
- throw new Error(`Failed to fetch latest version: ${res.statusText}`);
72912
+ throw new Error(
72913
+ `Failed to fetch latest version: ${res.statusText || res.status}`
72914
+ );
72801
72915
  }
72802
72916
  const data = await res.json();
72803
72917
  return data;
@@ -72846,7 +72960,7 @@ mutation addPendingDocumentMutation(
72846
72960
  }
72847
72961
  if (statusResponse.status !== 202) {
72848
72962
  const error = new Error(
72849
- statusResponseBody.message || `Failed to check workflow status: ${statusResponse.statusText}`
72963
+ statusResponseBody.message || `Failed to check workflow status: ${statusResponse.statusText || statusResponse.status}`
72850
72964
  );
72851
72965
  error.errorCode = "WORKFLOW_STATUS_FAILED";
72852
72966
  throw error;
@@ -74222,52 +74336,14 @@ const Layout = ({ children }) => {
74222
74336
  children
74223
74337
  ));
74224
74338
  };
74225
- const ErrorDialog = (props) => {
74226
- return /* @__PURE__ */ React__default.createElement(
74227
- "div",
74228
- {
74229
- style: {
74230
- background: "#efefef",
74231
- display: "flex",
74232
- alignItems: "center",
74233
- justifyContent: "center"
74234
- }
74235
- },
74236
- /* @__PURE__ */ React__default.createElement("style", null, " body { margin: 0; } "),
74237
- /* @__PURE__ */ React__default.createElement(
74238
- "div",
74239
- {
74240
- style: {
74241
- background: "#fff",
74242
- maxWidth: "400px",
74243
- padding: "20px",
74244
- fontFamily: "'Inter', sans-serif",
74245
- borderRadius: "5px",
74246
- boxShadow: "0 6px 24px rgb(0 37 91 / 5%), 0 2px 4px rgb(0 37 91 / 3%)"
74247
- }
74248
- },
74249
- /* @__PURE__ */ React__default.createElement("h3", { style: { color: "#eb6337" } }, props.title),
74250
- /* @__PURE__ */ React__default.createElement("p", null, props.message, ":"),
74251
- /* @__PURE__ */ React__default.createElement(
74252
- "pre",
74253
- {
74254
- style: { marginTop: "1rem", overflowX: "auto" }
74255
- },
74256
- `${props.error}`
74257
- ),
74258
- /* @__PURE__ */ React__default.createElement("p", null, "See our", " ", /* @__PURE__ */ React__default.createElement(
74259
- "a",
74260
- {
74261
- className: "text-gray-600",
74262
- style: { textDecoration: "underline" },
74263
- href: "https://tina.io/docs/r/FAQ/",
74264
- target: "_blank"
74265
- },
74266
- " ",
74267
- "Error FAQ",
74268
- " "
74269
- ), " ", "for more information.")
74270
- )
74339
+ const TROUBLESHOOTING_URL = "https://tina.io/docs/tinacloud/troubleshooting";
74340
+ const TroubleshootingLink = () => /* @__PURE__ */ React__default.createElement("a", { href: TROUBLESHOOTING_URL, target: "_blank", rel: "noopener noreferrer" }, "Read the TinaCloud troubleshooting guide");
74341
+ const ErrorDialog = (props) => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, props.title && /* @__PURE__ */ React__default.createElement("h3", null, props.title), /* @__PURE__ */ React__default.createElement("p", null, props.message, ":"), /* @__PURE__ */ React__default.createElement("pre", { className: "overflow-x-auto" }, `${props.error}`), /* @__PURE__ */ React__default.createElement(TroubleshootingLink, null));
74342
+ const showErrorModal = (title, message, cms) => {
74343
+ if (cms.alerts.all.some((a) => a.level === "error")) return;
74344
+ cms.alerts.error(
74345
+ () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("p", null, message), /* @__PURE__ */ React__default.createElement(TroubleshootingLink, null)),
74346
+ { title }
74271
74347
  );
74272
74348
  };
74273
74349
  const LoadingPage = () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
@@ -75499,18 +75575,24 @@ const shouldAutoOpenCollectionDocument = ({
75499
75575
  ((_b = (_a = collection.documents) == null ? void 0 : _a.edges) == null ? void 0 : _b.length) === 1 && // Check to make sure the file is not a folder
75500
75576
  ((_e = (_d = (_c = collection.documents) == null ? void 0 : _c.edges[0]) == null ? void 0 : _d.node) == null ? void 0 : _e.__typename) !== "Folder";
75501
75577
  };
75502
- const UnableToLoadModal = ({ message }) => /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, null, "Unable to load"), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose" }, message)), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex-1" }), /* @__PURE__ */ React__default.createElement(
75503
- Button$2,
75578
+ const UnableToLoadModal = ({ message }) => /* @__PURE__ */ React__default.createElement(
75579
+ ErrorModal,
75504
75580
  {
75505
- style: { flexGrow: 1 },
75506
- className: "w-full",
75507
- variant: "primary",
75508
- onClick: () => {
75509
- window.location.reload();
75510
- }
75581
+ title: "Unable to Load",
75582
+ actions: /* @__PURE__ */ React__default.createElement(
75583
+ Button$2,
75584
+ {
75585
+ className: "w-full sm:w-auto",
75586
+ variant: "primary",
75587
+ onClick: () => {
75588
+ window.location.reload();
75589
+ }
75590
+ },
75591
+ "Reload"
75592
+ )
75511
75593
  },
75512
- "Reload"
75513
- ))));
75594
+ message
75595
+ );
75514
75596
  const isValidSortKey = (sortKey, collection) => {
75515
75597
  if (collection.fields) {
75516
75598
  const sortKeys = collection.fields.map((x) => x.name);
@@ -75984,18 +76066,18 @@ const RenderForm$1 = ({
75984
76066
  }, 10);
75985
76067
  } catch (error) {
75986
76068
  if (isSessionExpiredError(error)) throw error;
75987
- const defaultErrorText = "There was a problem saving your document.";
75988
76069
  if (error.message && error.message.includes(ERR_ALREADY_EXISTS)) {
75989
76070
  cms.alerts.error(
75990
- `${defaultErrorText} The filename "${form.values.filename}.${collection.format || "md"}" is already used for another document, please modify it.`
76071
+ `The filename "${form.values.filename}.${collection.format || "md"}" is already used for another document, please modify it.`,
76072
+ { title: "Save Failed" }
75991
76073
  );
75992
76074
  } else {
75993
76075
  cms.alerts.error(
75994
76076
  () => ErrorDialog({
75995
- title: defaultErrorText,
75996
76077
  message: "Tina caught an error while creating the file",
75997
76078
  error
75998
- })
76079
+ }),
76080
+ { title: "Save Failed" }
75999
76081
  );
76000
76082
  }
76001
76083
  throw new Error(
@@ -76245,10 +76327,10 @@ const RenderForm = ({
76245
76327
  if (isSessionExpiredError(error)) throw error;
76246
76328
  cms.alerts.error(
76247
76329
  () => ErrorDialog({
76248
- title: "There was a problem saving your document",
76249
76330
  message: "Tina caught an error while updating the page",
76250
76331
  error
76251
- })
76332
+ }),
76333
+ { title: "Save Failed" }
76252
76334
  );
76253
76335
  console.error(error);
76254
76336
  throw new Error(
@@ -76337,15 +76419,6 @@ function resolvePreviewPath(splat, baseOrigin = typeof window !== "undefined" ?
76337
76419
  return { path: "/", offOrigin: true };
76338
76420
  }
76339
76421
  }
76340
- const TROUBLESHOOTING_URL = "https://tina.io/docs/tinacloud/troubleshooting";
76341
- const ErrorModalContent = (props) => {
76342
- const { title, message } = props;
76343
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", null, title), /* @__PURE__ */ React__default.createElement("p", null, message), /* @__PURE__ */ React__default.createElement("a", { href: TROUBLESHOOTING_URL, target: "_blank", rel: "noopener noreferrer" }, "Learn more"));
76344
- };
76345
- const showErrorModal = (title, message, cms) => {
76346
- if (cms.alerts.all.some((a) => a.level === "error")) return;
76347
- cms.alerts.error(() => /* @__PURE__ */ React__default.createElement(ErrorModalContent, { title, message }));
76348
- };
76349
76422
  const getBackendType = (client) => {
76350
76423
  var _a, _b, _c;
76351
76424
  if (!client) return "other";
@@ -76498,19 +76571,27 @@ const CheckSchema = ({
76498
76571
  });
76499
76572
  }
76500
76573
  }, [cms, JSON.stringify(schemaJson || {}), url]);
76501
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, schemaMissingError ? /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, null, "Branch Not Found"), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose" }, "The current branch (", /* @__PURE__ */ React__default.createElement("span", { className: "font-bold" }, currentBranch), ") has either been merged or deleted.")), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex-1" }), /* @__PURE__ */ React__default.createElement(
76502
- Button$2,
76574
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, schemaMissingError ? /* @__PURE__ */ React__default.createElement(
76575
+ ErrorModal,
76503
76576
  {
76504
- style: { flexGrow: 1 },
76505
- className: "w-full",
76506
- variant: "primary",
76507
- onClick: () => {
76508
- window.localStorage.removeItem("tinacms-current-branch");
76509
- window.location.reload();
76510
- }
76577
+ title: "Branch Not Found",
76578
+ actions: /* @__PURE__ */ React__default.createElement(
76579
+ Button$2,
76580
+ {
76581
+ className: "w-full sm:w-auto",
76582
+ variant: "primary",
76583
+ onClick: () => {
76584
+ window.localStorage.removeItem("tinacms-current-branch");
76585
+ window.location.reload();
76586
+ }
76587
+ },
76588
+ "Switch back to default branch"
76589
+ )
76511
76590
  },
76512
- "Switch back to default branch"
76513
- )))) : children);
76591
+ "The current branch (",
76592
+ /* @__PURE__ */ React__default.createElement("span", { className: "font-bold" }, currentBranch),
76593
+ ") has either been merged or deleted."
76594
+ ) : children);
76514
76595
  };
76515
76596
  const TinaAdmin = ({
76516
76597
  preview,
@@ -76843,6 +76924,7 @@ export {
76843
76924
  EllipsisVerticalIcon,
76844
76925
  ErrorDialog,
76845
76926
  ErrorIcon,
76927
+ ErrorModal,
76846
76928
  EventBus,
76847
76929
  ExitIcon,
76848
76930
  FieldDescription,
@@ -77007,6 +77089,7 @@ export {
77007
77089
  safeAssertShape,
77008
77090
  sanitizeFilename,
77009
77091
  selectFieldClasses,
77092
+ showErrorModal,
77010
77093
  sortBranchListFn,
77011
77094
  staticRequest,
77012
77095
  tableHeadingStyle,
@@ -47,6 +47,10 @@ type BaseComponents = {
47
47
  children: JSX.Element;
48
48
  color?: string;
49
49
  };
50
+ textColor?: {
51
+ children: JSX.Element;
52
+ color: string;
53
+ };
50
54
  text?: {
51
55
  children: string;
52
56
  };
@@ -1,3 +1,4 @@
1
+ import { isSafeCssColor } from "@tinacms/mdx/sanitize-css-color";
1
2
  import { sanitizeUrl } from "@tinacms/mdx/sanitize-url";
2
3
  import React from "react";
3
4
  const TinaMarkdown = ({
@@ -15,6 +16,7 @@ const TinaMarkdown = ({
15
16
  return /* @__PURE__ */ React.createElement(MemoNode, { components, key: index, child });
16
17
  }));
17
18
  };
19
+ const safeColor = (value) => value && isSafeCssColor(value) ? value : void 0;
18
20
  const Leaf = (props) => {
19
21
  if (props.bold) {
20
22
  const { bold, ...rest } = props;
@@ -58,17 +60,24 @@ const Leaf = (props) => {
58
60
  }
59
61
  if (props.highlight) {
60
62
  const { highlight, highlightColor, ...rest } = props;
63
+ const color = safeColor(highlightColor);
61
64
  if (props.components.highlight) {
62
65
  const Component = props.components.highlight;
63
- return /* @__PURE__ */ React.createElement(Component, { color: highlightColor }, /* @__PURE__ */ React.createElement(Leaf, { ...rest }));
66
+ return /* @__PURE__ */ React.createElement(Component, { color }, /* @__PURE__ */ React.createElement(Leaf, { ...rest }));
64
67
  }
65
- return /* @__PURE__ */ React.createElement(
66
- "mark",
67
- {
68
- style: highlightColor ? { backgroundColor: highlightColor } : void 0
69
- },
70
- /* @__PURE__ */ React.createElement(Leaf, { ...rest })
71
- );
68
+ return /* @__PURE__ */ React.createElement("mark", { style: color ? { backgroundColor: color } : void 0 }, /* @__PURE__ */ React.createElement(Leaf, { ...rest }));
69
+ }
70
+ if (props.textColor) {
71
+ const { textColor, ...rest } = props;
72
+ const color = safeColor(textColor);
73
+ if (!color) {
74
+ return /* @__PURE__ */ React.createElement(Leaf, { ...rest });
75
+ }
76
+ if (props.components.textColor) {
77
+ const Component = props.components.textColor;
78
+ return /* @__PURE__ */ React.createElement(Component, { color }, /* @__PURE__ */ React.createElement(Leaf, { ...rest }));
79
+ }
80
+ return /* @__PURE__ */ React.createElement("span", { style: { color } }, /* @__PURE__ */ React.createElement(Leaf, { ...rest }));
72
81
  }
73
82
  if (props.components.text) {
74
83
  const Component = props.components.text;
@@ -22,19 +22,23 @@ export declare class Alerts {
22
22
  * login modal. Alerts already showing are left alone.
23
23
  */
24
24
  private suppressed;
25
- add(level: AlertLevel, message: string | React.FunctionComponent, timeout?: number): () => void;
25
+ add(level: AlertLevel, message: string | React.FunctionComponent, timeout?: number, title?: string): () => void;
26
26
  dismiss(alert: Alert): void;
27
27
  subscribe(cb: Callback): () => void;
28
28
  get all(): Alert[];
29
29
  info(message: string | React.FunctionComponent, timeout?: number): () => void;
30
30
  success(message: string | React.FunctionComponent, timeout?: number): () => void;
31
31
  warn(message: string | React.FunctionComponent, timeout?: number): () => void;
32
- error(message: string | React.FunctionComponent, timeout?: number): () => void;
32
+ error(message: string | React.FunctionComponent, options?: number | ErrorAlertOptions): () => void;
33
33
  }
34
34
  export type AlertLevel = 'info' | 'success' | 'warn' | 'error';
35
+ export interface ErrorAlertOptions {
36
+ title?: string;
37
+ }
35
38
  export interface Alert {
36
39
  id: string;
37
40
  level: AlertLevel;
38
41
  message: string | React.FunctionComponent;
39
42
  timeout: number;
43
+ title?: string;
40
44
  }
@@ -45,7 +45,7 @@ declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
45
45
  children?: React.ReactNode;
46
46
  } & Omit<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
47
47
  asChild?: boolean;
48
- }, "ref">, "value" | "disabled" | "onSelect"> & {
48
+ }, "ref">, "value" | "onSelect" | "disabled"> & {
49
49
  disabled?: boolean;
50
50
  forceMount?: boolean;
51
51
  keywords?: string[];
@@ -9,5 +9,6 @@ export interface DateFieldProps {
9
9
  }
10
10
  export declare const DEFAULT_DATE_DISPLAY_FORMAT = "MMM DD, YYYY";
11
11
  export declare const DEFAULT_TIME_DISPLAY_FORMAT = "h:mm A";
12
+ export declare const getHourCycle: (timeFormat?: string) => 12 | 24;
12
13
  export declare const format: (val: string, _name: string, field: DateFieldProps) => string;
13
14
  export declare const parse: (val: string) => string;
@@ -102,7 +102,7 @@ export declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
102
102
  ref?: React.Ref<HTMLDivElement>;
103
103
  } & {
104
104
  asChild?: boolean;
105
- }, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "value" | "disabled" | "onSelect"> & {
105
+ }, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "value" | "onSelect" | "disabled"> & {
106
106
  disabled?: boolean;
107
107
  onSelect?: (value: string) => void;
108
108
  value?: string;
@@ -65,6 +65,7 @@ export declare const Icons: {
65
65
  search: React.ForwardRefExoticComponent<Omit<LucideProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
66
66
  settings: React.ForwardRefExoticComponent<Omit<LucideProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
67
67
  highlight: React.ForwardRefExoticComponent<Omit<LucideProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
68
+ textColor: React.ForwardRefExoticComponent<Omit<LucideProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
68
69
  strikethrough: React.ForwardRefExoticComponent<Omit<LucideProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
69
70
  subscript: React.ForwardRefExoticComponent<Omit<LucideProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
70
71
  superscript: React.ForwardRefExoticComponent<Omit<LucideProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
@@ -4,3 +4,4 @@ export declare const StrikethroughToolbarButton: () => React.JSX.Element;
4
4
  export declare const ItalicToolbarButton: () => React.JSX.Element;
5
5
  export declare const CodeToolbarButton: () => React.JSX.Element;
6
6
  export declare const HighlightToolbarButton: () => React.JSX.Element;
7
+ export declare const TextColorToolbarButton: () => React.JSX.Element;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Leaf mark for coloured text. The mark's value is the CSS colour itself
3
+ * (`{ text, textColor: '#CC4141' }`) — there is no separate boolean flag.
4
+ */
5
+ export declare const TextColorPlugin: import("@udecode/plate/react").PlatePlugin<import("@udecode/plate").PluginConfig<"textColor", {}, {}, {}, {}>>;
@@ -177,6 +177,7 @@ export declare const Components: () => {
177
177
  a: typeof LinkElement;
178
178
  code: typeof CodeLeaf;
179
179
  highlight: ({ leaf, ...props }: React.ComponentProps<typeof PlateLeaf>) => React.JSX.Element;
180
+ textColor: ({ leaf, ...props }: React.ComponentProps<typeof PlateLeaf>) => React.JSX.Element;
180
181
  underline: React.ForwardRefExoticComponent<Omit<Omit<import("@udecode/plate/react").PlateLeafProps<import("@udecode/plate").TText, import("@udecode/plate").AnyPluginConfig>, keyof {
181
182
  className?: string;
182
183
  style?: React.CSSProperties;
@@ -1,5 +1,5 @@
1
- import type { HeadingLevel, ToolbarOverrideType } from '@tinacms/schema-tools';
2
- export type { HeadingLevel, ToolbarOverrideType };
1
+ import type { HeadingLevel, RichTextColorOption, ToolbarOverrideType } from '@tinacms/schema-tools';
2
+ export type { HeadingLevel, RichTextColorOption, ToolbarOverrideType };
3
3
  export declare const STANDARD_ICON_WIDTH = 32;
4
4
  export declare const HEADING_ICON_WITH_TEXT = 127;
5
5
  export declare const HEADING_ICON_ONLY = 58;
@@ -11,4 +11,5 @@ export type ToolbarOverrides = {
11
11
  toolbar?: ToolbarOverrideType[];
12
12
  showFloatingToolbar?: boolean;
13
13
  headingLevels?: HeadingLevel[];
14
+ textColors?: RichTextColorOption[];
14
15
  };
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
2
  import { type ReactNode } from 'react';
3
+ import { type HeadingLevel } from '@tinacms/schema-tools';
3
4
  import type { Form } from '../../../../../forms';
4
5
  import type { MdxTemplate } from '../types';
5
- import { type HeadingLevel } from '@tinacms/schema-tools';
6
- import type { ToolbarOverrides, ToolbarOverrideType } from './toolbar-overrides';
6
+ import type { RichTextColorOption, ToolbarOverrideType, ToolbarOverrides } from './toolbar-overrides';
7
7
  interface ToolbarContextProps {
8
8
  tinaForm: Form;
9
9
  templates: MdxTemplate[];
@@ -16,8 +16,10 @@ interface ToolbarContextProps {
16
16
  * from "use the legacy default" without re-deriving the check.
17
17
  */
18
18
  headingLevelsConfigured: boolean;
19
+ /** Palette for the text colour dropdown (schema value or default). */
20
+ textColors: readonly RichTextColorOption[];
19
21
  }
20
- interface ToolbarProviderProps extends Omit<ToolbarContextProps, 'headingLevels' | 'headingLevelsConfigured'> {
22
+ interface ToolbarProviderProps extends Omit<ToolbarContextProps, 'headingLevels' | 'headingLevelsConfigured' | 'textColors'> {
21
23
  children: ReactNode;
22
24
  }
23
25
  export declare const ToolbarProvider: React.FC<ToolbarProviderProps>;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export interface ErrorModalProps {
3
+ title: string;
4
+ actions: React.ReactNode;
5
+ close?: () => void;
6
+ children: React.ReactNode;
7
+ }
8
+ export declare const ErrorModal: ({ title, actions, close, children, }: ErrorModalProps) => React.JSX.Element;
@@ -2,3 +2,4 @@ export * from './modal-provider';
2
2
  export * from './modal';
3
3
  export * from './fullscreen-modal';
4
4
  export * from './popup-modal';
5
+ export * from './error-modal';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "tinacms",
3
3
  "type": "module",
4
4
  "typings": "dist/index.d.ts",
5
- "version": "3.14.3",
5
+ "version": "3.15.0",
6
6
  "main": "dist/index.js",
7
7
  "module": "./dist/index.js",
8
8
  "exports": {
@@ -104,19 +104,18 @@
104
104
  "react-dnd-html5-backend": "^16.0.1",
105
105
  "react-dropzone": "14.2.3",
106
106
  "react-final-form": "^6.5.9",
107
- "react-router-dom": "^6.30.3",
107
+ "react-router-dom": "^7.18.4",
108
108
  "react-use": "^17.6.0",
109
109
  "tailwind-merge": "^2.6.0",
110
110
  "webfontloader": "1.6.28",
111
111
  "yup": "^1.6.1",
112
112
  "zod": "^3.24.2",
113
- "@tinacms/mdx": "^2.3.0",
114
113
  "@tinacms/bridge": "^0.3.1",
115
- "@tinacms/schema-tools": "^2.10.1",
116
- "@tinacms/search": "^0.0.0-f3cf692-20261006035700"
114
+ "@tinacms/schema-tools": "^2.11.0",
115
+ "@tinacms/mdx": "^2.4.0",
116
+ "@tinacms/search": "^1.2.26"
117
117
  },
118
118
  "devDependencies": {
119
- "@graphql-tools/utils": "^10.8.1",
120
119
  "@testing-library/dom": "^10.4.0",
121
120
  "@testing-library/jest-dom": "^6.7.0",
122
121
  "@testing-library/react": "^16.2.0",
@@ -132,7 +131,7 @@
132
131
  "identity-obj-proxy": "^3.0.0",
133
132
  "jest-file-snapshot": "^0.7.0",
134
133
  "lowlight": "^3.3.0",
135
- "next": "15.5.21",
134
+ "next": "15.5.27",
136
135
  "react": "^18.3.1",
137
136
  "react-dom": "^18.3.1",
138
137
  "react-is": "^18.3.1",