@kyro-cms/admin 0.9.8 → 0.10.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/dist/index.cjs CHANGED
@@ -3861,33 +3861,63 @@ function RichTextField({
3861
3861
  error,
3862
3862
  disabled
3863
3863
  }) {
3864
- const [isExpanded, setIsExpanded] = React.useState(false);
3865
- const [panelWidth, setPanelWidth] = React.useState(0);
3866
- const [isMediaPickerOpen, setIsMediaPickerOpen] = React.useState(false);
3867
3864
  const [isMounted, setIsMounted] = React.useState(false);
3868
3865
  React.useEffect(() => {
3869
3866
  setIsMounted(true);
3870
3867
  }, []);
3868
+ if (!isMounted) {
3869
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldLayout, { field: field3, error, children: /* @__PURE__ */ jsxRuntime.jsxs(
3870
+ "div",
3871
+ {
3872
+ className: `border rounded-lg bg-[var(--kyro-bg)] overflow-hidden border-[var(--kyro-border)] flex flex-col shadow-sm transition-all duration-200
3873
+ ${error ? "border-[var(--kyro-error)] shadow-[0_0_0_1px_var(--kyro-error)]" : "border-[var(--kyro-border)]"}
3874
+ ${disabled ? "opacity-60 cursor-not-allowed" : ""}`,
3875
+ children: [
3876
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1.5 p-1.5 border-b border-[var(--kyro-border)] bg-[var(--kyro-bg-secondary)] rounded-t-lg h-[40px]" }),
3877
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto min-h-[160px] max-h-[400px] p-4" })
3878
+ ]
3879
+ }
3880
+ ) });
3881
+ }
3882
+ return /* @__PURE__ */ jsxRuntime.jsx(
3883
+ RichTextEditor,
3884
+ {
3885
+ field: field3,
3886
+ value,
3887
+ onChange,
3888
+ error,
3889
+ disabled
3890
+ }
3891
+ );
3892
+ }
3893
+ function RichTextEditor({
3894
+ field: field3,
3895
+ value,
3896
+ onChange,
3897
+ error,
3898
+ disabled
3899
+ }) {
3900
+ const [isExpanded, setIsExpanded] = React.useState(false);
3901
+ const [panelWidth, setPanelWidth] = React.useState(0);
3902
+ const [isMediaPickerOpen, setIsMediaPickerOpen] = React.useState(false);
3871
3903
  React.useEffect(() => {
3872
3904
  if (!isExpanded) {
3873
3905
  setPanelWidth(0);
3874
3906
  return;
3875
3907
  }
3908
+ const panel = document.querySelector('[data-kyro-slide-panel="true"]');
3876
3909
  const updateWidth = () => {
3877
- const panel2 = document.querySelector('[data-kyro-slide-panel="true"]');
3878
- if (panel2) {
3879
- setPanelWidth(panel2.getBoundingClientRect().width);
3910
+ if (panel) {
3911
+ setPanelWidth(panel.getBoundingClientRect().width);
3880
3912
  } else {
3881
3913
  setPanelWidth(0);
3882
3914
  }
3883
3915
  };
3884
3916
  updateWidth();
3885
- let observer = null;
3886
- const panel = document.querySelector('[data-kyro-slide-panel="true"]');
3887
- if (panel && typeof ResizeObserver !== "undefined") {
3888
- observer = new ResizeObserver(() => {
3889
- updateWidth();
3890
- });
3917
+ const observer = new MutationObserver(() => {
3918
+ updateWidth();
3919
+ });
3920
+ if (panel) {
3891
3921
  observer.observe(panel);
3892
3922
  }
3893
3923
  window.addEventListener("resize", updateWidth);
@@ -3925,7 +3955,7 @@ function RichTextField({
3925
3955
  extensionTextStyle.TextStyle,
3926
3956
  Color__default.default
3927
3957
  ],
3928
- content: value || { type: "doc", content: [] },
3958
+ content: Array.isArray(value) ? { type: "doc", content: value } : value || { type: "doc", content: [] },
3929
3959
  editable: !disabled,
3930
3960
  onUpdate: ({ editor: editor2 }) => {
3931
3961
  onChange(editor2.getJSON());
@@ -3938,23 +3968,9 @@ function RichTextField({
3938
3968
  });
3939
3969
  React.useEffect(() => {
3940
3970
  if (editor && value && JSON.stringify(value) !== JSON.stringify(editor.getJSON())) {
3941
- editor.commands.setContent(value);
3971
+ editor.commands.setContent(Array.isArray(value) ? { type: "doc", content: value } : value);
3942
3972
  }
3943
3973
  }, [value, editor]);
3944
- if (!isMounted) {
3945
- return /* @__PURE__ */ jsxRuntime.jsx(FieldLayout, { field: field3, error, children: /* @__PURE__ */ jsxRuntime.jsxs(
3946
- "div",
3947
- {
3948
- className: `border rounded-lg bg-[var(--kyro-bg)] overflow-hidden border-[var(--kyro-border)] flex flex-col shadow-sm transition-all duration-200
3949
- ${error ? "border-[var(--kyro-error)] shadow-[0_0_0_1px_var(--kyro-error)]" : "border-[var(--kyro-border)]"}
3950
- ${disabled ? "opacity-60 cursor-not-allowed" : ""}`,
3951
- children: [
3952
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1.5 p-1.5 border-b border-[var(--kyro-border)] bg-[var(--kyro-bg-secondary)] rounded-t-lg h-[40px]" }),
3953
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto min-h-[160px] max-h-[400px] p-4" })
3954
- ]
3955
- }
3956
- ) });
3957
- }
3958
3974
  return /* @__PURE__ */ jsxRuntime.jsxs(FieldLayout, { field: field3, error, children: [
3959
3975
  isExpanded ? (
3960
3976
  // Maximize mode placeholder inside form
@@ -5888,6 +5904,7 @@ function createNewBlock(type) {
5888
5904
  return {
5889
5905
  id: Math.random().toString(36).substr(2, 9),
5890
5906
  type,
5907
+ name: "",
5891
5908
  data,
5892
5909
  options,
5893
5910
  children,
@@ -7525,6 +7542,18 @@ var BlockEditModal = ({
7525
7542
  accentClass: theme.border,
7526
7543
  children: [
7527
7544
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
7545
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7546
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-[10px] font-medium text-[var(--kyro-text-muted)] mb-1 block", children: "Block Name" }),
7547
+ /* @__PURE__ */ jsxRuntime.jsx(
7548
+ "input",
7549
+ {
7550
+ value: blockData?.name || "",
7551
+ onChange: (e) => updateBlock(block3.id, { name: e.target.value }),
7552
+ placeholder: blockSchema?.label || block3.type,
7553
+ className: "w-full bg-[var(--kyro-bg-primary)] border border-[var(--kyro-border)] rounded-lg px-3 py-2 text-sm text-[var(--kyro-text-primary)] outline-none focus:border-[var(--kyro-primary)] transition-colors"
7554
+ }
7555
+ )
7556
+ ] }),
7528
7557
  renderFields(),
7529
7558
  children.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-4 border-t border-[var(--kyro-border)]", children: [
7530
7559
  /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "text-[10px] font-medium text-[var(--kyro-text-muted)] mb-1.5 block", children: [
@@ -7636,7 +7665,7 @@ var ChildBlocksTree = ({
7636
7665
  blockIcons[child.type] && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 rounded bg-[var(--kyro-surface-accent)] flex items-center justify-center text-[var(--kyro-text-secondary)]", children: blockIcons[child.type] }),
7637
7666
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
7638
7667
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs font-medium text-[var(--kyro-text-secondary)] truncate", children: [
7639
- getBlockLabel(child.type),
7668
+ getBlockDisplayLabel(child),
7640
7669
  child.data?.text ? ` - ${child.data.text.slice(0, 30)}` : "",
7641
7670
  child.data?.heading ? ` - ${child.data.heading.slice(0, 30)}` : ""
7642
7671
  ] }),
@@ -7857,7 +7886,7 @@ var NestedChildBlocks = ({
7857
7886
  blockIcons[child.type] && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 rounded bg-[var(--kyro-surface-accent)] flex items-center justify-center text-[var(--kyro-text-secondary)]", children: blockIcons[child.type] }),
7858
7887
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
7859
7888
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs font-medium text-[var(--kyro-text-secondary)] truncate", children: [
7860
- getBlockLabel(child.type),
7889
+ getBlockDisplayLabel(child),
7861
7890
  child.data?.text ? ` - ${child.data.text.slice(0, 30)}` : "",
7862
7891
  child.data?.heading ? ` - ${child.data.heading.slice(0, 30)}` : ""
7863
7892
  ] }),
@@ -8571,7 +8600,7 @@ var blockIcons = {
8571
8600
  function getBlockComponent(type) {
8572
8601
  return BLOCK_COMPONENTS[type] || null;
8573
8602
  }
8574
- function getBlockLabel(type) {
8603
+ function getBlockLabel2(type) {
8575
8604
  const labelMap = {
8576
8605
  // Primitives
8577
8606
  paragraph: "Paragraph",
@@ -8614,6 +8643,11 @@ function getBlockLabel(type) {
8614
8643
  };
8615
8644
  return labelMap[type] || type;
8616
8645
  }
8646
+ function getBlockDisplayLabel(block3) {
8647
+ const name = block3.name;
8648
+ if (name && name.trim()) return name.trim();
8649
+ return getBlockLabel2(block3.type);
8650
+ }
8617
8651
  function getBlockPreviewSnippet(data, blockSchema) {
8618
8652
  if (blockSchema?.fields) {
8619
8653
  for (const field3 of blockSchema.fields) {
@@ -8642,16 +8676,32 @@ var SortableBlockComponent = ({
8642
8676
  transition,
8643
8677
  isDragging
8644
8678
  } = sortable.useSortable({ id: block3.id });
8645
- const { removeBlock } = useBlockActions();
8679
+ const { removeBlock, updateBlock } = useBlockActions();
8646
8680
  const isEditing = editingBlockId === block3.id;
8647
8681
  const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);
8682
+ const [editingName, setEditingName] = React.useState(false);
8683
+ const [nameDraft, setNameDraft] = React.useState(block3.name || "");
8684
+ const nameInputRef = React.useRef(null);
8685
+ React.useEffect(() => {
8686
+ if (editingName && nameInputRef.current) {
8687
+ nameInputRef.current.focus();
8688
+ nameInputRef.current.select();
8689
+ }
8690
+ }, [editingName]);
8691
+ const commitName = React.useCallback(() => {
8692
+ setEditingName(false);
8693
+ const trimmed = nameDraft.trim();
8694
+ if (trimmed !== (block3.name || "").trim()) {
8695
+ updateBlock(block3.id, { name: trimmed || "" });
8696
+ }
8697
+ }, [nameDraft, block3.name, block3.id, updateBlock]);
8648
8698
  const style = {
8649
8699
  transform: utilities.CSS.Transform.toString(transform),
8650
8700
  transition,
8651
8701
  zIndex: isDragging ? 10 : 1,
8652
8702
  opacity: isDragging ? 0.8 : 1
8653
8703
  };
8654
- const itemLabel = getBlockLabel(block3.type);
8704
+ const itemLabel = getBlockDisplayLabel(block3);
8655
8705
  const data = block3.data || {};
8656
8706
  const previewSnippet = getBlockPreviewSnippet(data, blockSchema);
8657
8707
  if (compact) {
@@ -8673,7 +8723,36 @@ var SortableBlockComponent = ({
8673
8723
  }
8674
8724
  ),
8675
8725
  blockIcons[block3.type] && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[var(--kyro-text-secondary)] flex-shrink-0", children: blockIcons[block3.type] }),
8676
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-[var(--kyro-text-secondary)] truncate max-w-[120px]", children: itemLabel }),
8726
+ editingName ? /* @__PURE__ */ jsxRuntime.jsx(
8727
+ "input",
8728
+ {
8729
+ ref: nameInputRef,
8730
+ value: nameDraft,
8731
+ onChange: (e) => setNameDraft(e.target.value),
8732
+ onBlur: commitName,
8733
+ onKeyDown: (e) => {
8734
+ if (e.key === "Enter") commitName();
8735
+ if (e.key === "Escape") {
8736
+ setNameDraft(block3.name || "");
8737
+ setEditingName(false);
8738
+ }
8739
+ },
8740
+ onClick: (e) => e.stopPropagation(),
8741
+ className: "flex-1 min-w-0 bg-[var(--kyro-surface-accent)] border border-[var(--kyro-primary)] rounded px-1.5 py-0.5 text-[10px] font-medium text-[var(--kyro-text-primary)] outline-none"
8742
+ }
8743
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
8744
+ "span",
8745
+ {
8746
+ onClick: (e) => {
8747
+ e.stopPropagation();
8748
+ setNameDraft(block3.name || "");
8749
+ setEditingName(true);
8750
+ },
8751
+ className: "font-medium text-[var(--kyro-text-secondary)] truncate max-w-[120px] cursor-text hover:text-[var(--kyro-text-primary)] transition-colors",
8752
+ title: "Click to rename",
8753
+ children: itemLabel
8754
+ }
8755
+ ),
8677
8756
  showDeleteConfirm ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", onClick: (e) => e.stopPropagation(), children: [
8678
8757
  /* @__PURE__ */ jsxRuntime.jsx(
8679
8758
  "button",
@@ -8755,13 +8834,43 @@ var SortableBlockComponent = ({
8755
8834
  children: [
8756
8835
  blockIcons[block3.type] && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[var(--kyro-text-secondary)]", children: blockIcons[block3.type] }),
8757
8836
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
8758
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs font-semibold text-[var(--kyro-text-secondary)] truncate", children: [
8759
- itemLabel,
8760
- previewSnippet && typeof previewSnippet === "string" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[var(--kyro-text-muted)] font-normal ml-1.5", children: [
8761
- "- ",
8762
- previewSnippet.length > 40 ? `${previewSnippet.slice(0, 40)}...` : previewSnippet
8763
- ] })
8764
- ] }),
8837
+ editingName ? /* @__PURE__ */ jsxRuntime.jsx(
8838
+ "input",
8839
+ {
8840
+ ref: nameInputRef,
8841
+ value: nameDraft,
8842
+ onChange: (e) => setNameDraft(e.target.value),
8843
+ onBlur: commitName,
8844
+ onKeyDown: (e) => {
8845
+ if (e.key === "Enter") commitName();
8846
+ if (e.key === "Escape") {
8847
+ setNameDraft(block3.name || "");
8848
+ setEditingName(false);
8849
+ }
8850
+ },
8851
+ onClick: (e) => e.stopPropagation(),
8852
+ placeholder: getBlockLabel2(block3.type),
8853
+ className: "w-full bg-[var(--kyro-surface-accent)] border border-[var(--kyro-primary)] rounded px-2 py-0.5 text-xs font-semibold text-[var(--kyro-text-primary)] outline-none"
8854
+ }
8855
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
8856
+ "div",
8857
+ {
8858
+ onClick: (e) => {
8859
+ e.stopPropagation();
8860
+ setNameDraft(block3.name || "");
8861
+ setEditingName(true);
8862
+ },
8863
+ className: "text-xs font-semibold text-[var(--kyro-text-secondary)] truncate cursor-text hover:text-[var(--kyro-text-primary)] transition-colors",
8864
+ title: "Click to rename",
8865
+ children: [
8866
+ itemLabel,
8867
+ previewSnippet && typeof previewSnippet === "string" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[var(--kyro-text-muted)] font-normal ml-1.5", children: [
8868
+ "- ",
8869
+ previewSnippet.length > 40 ? `${previewSnippet.slice(0, 40)}...` : previewSnippet
8870
+ ] })
8871
+ ]
8872
+ }
8873
+ ),
8765
8874
  blockSchema?.admin?.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] text-[var(--kyro-text-muted)] mt-0.5 truncate opacity-80", children: blockSchema.admin.description })
8766
8875
  ] }),
8767
8876
  block3.children && Array.isArray(block3.children) && block3.children.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] bg-[var(--kyro-surface-accent)] px-2 py-0.5 rounded text-[var(--kyro-text-muted)] font-medium", children: [
@@ -14610,7 +14719,6 @@ var samplePlugin = {
14610
14719
  description: "A tiny sample plugin to demonstrate the extensibility surface",
14611
14720
  hooks: {
14612
14721
  onAdminReady: () => {
14613
- console.log("[ Kyro Admin ] sample-plugin: onAdminReady executed");
14614
14722
  return;
14615
14723
  }
14616
14724
  }
@@ -14624,7 +14732,6 @@ var samplePlugin2 = {
14624
14732
  description: "Second MVP plugin demonstrating beforeDeploy hook",
14625
14733
  hooks: {
14626
14734
  beforeDeploy: (ctx) => {
14627
- console.log("[Kyro Admin] sample-plugin-2 beforeDeploy");
14628
14735
  return { success: true };
14629
14736
  }
14630
14737
  }
@@ -14915,7 +15022,6 @@ export function c(size) {
14915
15022
  function debug(namespace) {
14916
15023
  function d(...args) {
14917
15024
  if (typeof localStorage !== "undefined" && localStorage.getItem("DEBUG")) {
14918
- console.log(namespace, ...args);
14919
15025
  }
14920
15026
  }
14921
15027
  d.enabled = false;
@@ -14935,9 +15041,33 @@ export default debug;
14935
15041
  "kyro:config": resolvedConfig
14936
15042
  }
14937
15043
  },
15044
+ build: {
15045
+ rollupOptions: {
15046
+ output: {
15047
+ manualChunks(id) {
15048
+ if (id.includes("@tiptap") || id.includes("prosemirror")) {
15049
+ return "vendor-tiptap";
15050
+ }
15051
+ }
15052
+ }
15053
+ }
15054
+ },
14938
15055
  optimizeDeps: {
14939
15056
  include: [
14940
- "use-sync-external-store"
15057
+ "use-sync-external-store",
15058
+ "@tiptap/core",
15059
+ "@tiptap/react",
15060
+ "@tiptap/pm",
15061
+ "@tiptap/starter-kit",
15062
+ "@tiptap/extension-link",
15063
+ "@tiptap/extension-image",
15064
+ "@tiptap/extension-text-align",
15065
+ "@tiptap/extension-underline",
15066
+ "@tiptap/extension-highlight",
15067
+ "@tiptap/extension-task-list",
15068
+ "@tiptap/extension-task-item",
15069
+ "@tiptap/extension-text-style",
15070
+ "@tiptap/extension-color"
14941
15071
  ],
14942
15072
  exclude: ["debug", "react/compiler-runtime"]
14943
15073
  },
@@ -14947,7 +15077,31 @@ export default debug;
14947
15077
  __KYRO_ADMIN_CONFIG_FILE__: JSON.stringify(configFile)
14948
15078
  },
14949
15079
  ssr: {
14950
- noExternal: ["@kyro-cms/admin", "@kyro-cms/core"]
15080
+ noExternal: [
15081
+ "@kyro-cms/admin",
15082
+ "@kyro-cms/core",
15083
+ "@tiptap/core",
15084
+ "@tiptap/react",
15085
+ "@tiptap/pm",
15086
+ "@tiptap/starter-kit",
15087
+ "@tiptap/extension-link",
15088
+ "@tiptap/extension-image",
15089
+ "@tiptap/extension-text-align",
15090
+ "@tiptap/extension-underline",
15091
+ "@tiptap/extension-highlight",
15092
+ "@tiptap/extension-task-list",
15093
+ "@tiptap/extension-task-item",
15094
+ "@tiptap/extension-text-style",
15095
+ "@tiptap/extension-color",
15096
+ "prosemirror-model",
15097
+ "prosemirror-state",
15098
+ "prosemirror-view",
15099
+ "prosemirror-schema-list",
15100
+ "prosemirror-commands",
15101
+ "prosemirror-keymap",
15102
+ "prosemirror-transform",
15103
+ "prosemirror-inputrules"
15104
+ ]
14951
15105
  }
14952
15106
  }
14953
15107
  });