@mulmocast/deck 0.6.0 → 0.7.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/lib/blocks.js CHANGED
@@ -1,4 +1,4 @@
1
- import { escapeHtml, c, generateSlideId, renderInlineMarkup, blockTitle, resolveChangeColor, resolveAccent, dp } from "./utils.js";
1
+ import { escapeHtml, c, generateSlideId, renderInlineMarkup, blockTitle, resolveChangeColor, resolveAccent, dp, di } from "./utils.js";
2
2
  /**
3
3
  * Map a TextSize variant to its Tailwind classes.
4
4
  * default — body / muted (the original 0.1.x behavior; emitted only when neither size nor numeric fontSize is set).
@@ -191,7 +191,10 @@ const renderBullets = (block, path = "") => {
191
191
  const itemCls = itemStyle.fontCls === blockStyle.fontCls && itemStyle.colorCls === blockStyle.colorCls ? "" : ` ${itemStyle.fontCls} ${itemStyle.colorCls}`;
192
192
  // For string items, the editable target is `path.items[i]`. For object items, it's `path.items[i].text`.
193
193
  const itemPath = path ? (typeof item === "string" ? `${path}.items[${i}]` : `${path}.items[${i}].text`) : "";
194
- return ` <li class="flex flex-col gap-1${itemCls}"><div class="flex gap-2">${markerHtml}<span${dp(itemPath)}>${renderInlineMarkup(text)}</span></div>${subHtml}</li>`;
194
+ // The bullet `<li>` itself carries `data-mulmo-item-path` so editors can drag-reorder; the inner
195
+ // span keeps `data-mulmo-path` for the text edit target.
196
+ const itemRoot = path ? `${path}.items[${i}]` : "";
197
+ return ` <li class="flex flex-col gap-1${itemCls}"${di(itemRoot)}><div class="flex gap-2">${markerHtml}<span${dp(itemPath)}>${renderInlineMarkup(text)}</span></div>${subHtml}</li>`;
195
198
  })
196
199
  .join("\n");
197
200
  return `<${tag} class="space-y-2 ${blockStyle.fontCls} ${blockStyle.colorCls} font-body">\n${items}\n</${tag}>`;
@@ -32,7 +32,7 @@ const buildColumnCard = (col, basePath) => {
32
32
  if (col.footer) {
33
33
  inner.push(`<p class="text-sm text-d-dim font-body mt-auto pt-3"${dp(`${basePath}.footer`)}>${renderInlineMarkup(col.footer)}</p>`);
34
34
  }
35
- return cardWrap(accent, inner.join("\n"), "flex-1");
35
+ return cardWrap(accent, inner.join("\n"), "flex-1", basePath);
36
36
  };
37
37
  export const layoutColumns = (data) => {
38
38
  const cols = data.columns || [];
@@ -33,7 +33,7 @@ export const layoutGrid = (data) => {
33
33
  // Asymmetric grids: items can span multiple columns. Class names are mapped explicitly so the JIT compiler keeps them.
34
34
  const SPAN_CLS = { 1: "", 2: "col-span-2", 3: "col-span-3", 4: "col-span-4" };
35
35
  const spanCls = item.span && item.span > 1 ? SPAN_CLS[item.span] || "" : "";
36
- parts.push(cardWrap(itemAccent, inner.join("\n"), spanCls));
36
+ parts.push(cardWrap(itemAccent, inner.join("\n"), spanCls, base));
37
37
  });
38
38
  parts.push(`</div>`);
39
39
  if (data.footer) {
@@ -1,8 +1,8 @@
1
- import { renderInlineMarkup, c, slideHeader, renderOptionalCallout, resolveItemColor, dp } from "../utils.js";
1
+ import { renderInlineMarkup, c, slideHeader, renderOptionalCallout, resolveItemColor, dp, di } from "../utils.js";
2
2
  const buildManifestoCard = (line, slideAccent, basePath) => {
3
3
  const color = resolveItemColor(line.accentColor, slideAccent);
4
4
  const parts = [];
5
- parts.push(`<div class="relative bg-d-card rounded-lg shadow-md overflow-hidden flex flex-col">`);
5
+ parts.push(`<div class="relative bg-d-card rounded-lg shadow-md overflow-hidden flex flex-col"${di(basePath)}>`);
6
6
  parts.push(` <div class="absolute left-0 top-0 bottom-0 w-1 bg-${c(color)}"></div>`);
7
7
  parts.push(` <div class="px-5 py-4 pl-6 flex-1">`);
8
8
  parts.push(` <h3 class="text-lg font-bold text-d-text font-body leading-snug"${dp(`${basePath}.title`)}>${renderInlineMarkup(line.title)}</h3>`);
@@ -1,4 +1,4 @@
1
- import { renderInlineMarkup, c, resolveItemColor, resolveChangeColor, centeredSlideHeader, renderOptionalCallout, dp } from "../utils.js";
1
+ import { renderInlineMarkup, c, resolveItemColor, resolveChangeColor, centeredSlideHeader, renderOptionalCallout, dp, di } from "../utils.js";
2
2
  export const layoutStats = (data) => {
3
3
  const stats = data.stats || [];
4
4
  const parts = [];
@@ -8,7 +8,7 @@ export const layoutStats = (data) => {
8
8
  stats.forEach((stat, i) => {
9
9
  const color = resolveItemColor(stat.color, data.accentColor);
10
10
  const base = `stats[${i}]`;
11
- parts.push(`<div class="flex-1 bg-d-card rounded-lg shadow-lg p-10 text-center">`);
11
+ parts.push(`<div class="flex-1 bg-d-card rounded-lg shadow-lg p-10 text-center"${di(base)}>`);
12
12
  parts.push(` <div class="h-[3px] bg-${c(color)} rounded-full w-12 mx-auto mb-6"></div>`);
13
13
  if (stat.numLabel) {
14
14
  parts.push(` <p class="font-accent font-extrabold text-${c(color)} text-sm tracking-wider mb-2"${dp(`${base}.numLabel`)}>${renderInlineMarkup(stat.numLabel)}</p>`);
@@ -1,4 +1,4 @@
1
- import { renderInlineMarkup, c, resolveItemColor, centeredSlideHeader, dp } from "../utils.js";
1
+ import { renderInlineMarkup, c, resolveItemColor, centeredSlideHeader, dp, di } from "../utils.js";
2
2
  export const layoutTimeline = (data) => {
3
3
  const parts = [];
4
4
  const items = data.items || [];
@@ -14,7 +14,7 @@ export const layoutTimeline = (data) => {
14
14
  const dotInner = item.done ? "bg-d-text" : `bg-${c(color)}`;
15
15
  const hotRing = item.hot ? ` ring-2 ring-${c(color)} ring-offset-2 ring-offset-d-bg` : "";
16
16
  const base = `items[${i}]`;
17
- parts.push(`<div class="flex-1 flex flex-col items-center text-center relative z-10">`);
17
+ parts.push(`<div class="flex-1 flex flex-col items-center text-center relative z-10"${di(base)}>`);
18
18
  parts.push(` <div class="w-10 h-10 rounded-full ${dotBorder} flex items-center justify-center shadow-lg${hotRing}">`);
19
19
  parts.push(` <div class="w-4 h-4 rounded-full ${dotInner}"></div>`);
20
20
  parts.push(` </div>`);
package/lib/utils.d.ts CHANGED
@@ -9,6 +9,16 @@ export declare const escapeHtml: (s: string) => string;
9
9
  * Empty path → empty string, so callers can pass `dp(path)` unconditionally.
10
10
  */
11
11
  export declare const dp: (path: string) => string;
12
+ /**
13
+ * Emit a `data-mulmo-item-path="..."` attribute (with leading space) for a drag-reorderable
14
+ * list-item container (e.g. a `<li>` in a bullets block, a stats card, a timeline step, a
15
+ * manifesto line, a columns card, a grid item). The path identifies the item ROOT in the
16
+ * SlideLayout JSON — siblings (items in the same parent array) share the same parent prefix.
17
+ *
18
+ * Distinct from `data-mulmo-path` (which points at a leaf editable text). This attribute is
19
+ * used by editor UIs to wire drag-and-drop reorder.
20
+ */
21
+ export declare const di: (path: string) => string;
12
22
  /** Compose a child path: `dpJoin("columns[0]", "title")` → `columns[0].title`. */
13
23
  export declare const dpJoin: (base: string, segment: string) => string;
14
24
  /** Escape HTML and convert newlines to <br> */
@@ -53,8 +63,8 @@ export declare const isSafeCssBackground: (s: string) => boolean;
53
63
  export declare const numBadge: (num: number, colorKey: string) => string;
54
64
  /** Render an icon in a square container */
55
65
  export declare const iconSquare: (icon: string, colorKey: string) => string;
56
- /** Render a card wrapper with accent top bar */
57
- export declare const cardWrap: (accentColor: string, innerHtml: string, extraClass?: string) => string;
66
+ /** Render a card wrapper with accent top bar. Pass `itemPath` to emit a drag-reorder anchor. */
67
+ export declare const cardWrap: (accentColor: string, innerHtml: string, extraClass?: string, itemPath?: string) => string;
58
68
  /** Render a callout bar at the bottom of a slide */
59
69
  export declare const renderCalloutBar: (obj: {
60
70
  text: string;
package/lib/utils.js CHANGED
@@ -15,6 +15,16 @@ export const escapeHtml = (s) => {
15
15
  * Empty path → empty string, so callers can pass `dp(path)` unconditionally.
16
16
  */
17
17
  export const dp = (path) => (path ? ` data-mulmo-path="${escapeHtml(path)}"` : "");
18
+ /**
19
+ * Emit a `data-mulmo-item-path="..."` attribute (with leading space) for a drag-reorderable
20
+ * list-item container (e.g. a `<li>` in a bullets block, a stats card, a timeline step, a
21
+ * manifesto line, a columns card, a grid item). The path identifies the item ROOT in the
22
+ * SlideLayout JSON — siblings (items in the same parent array) share the same parent prefix.
23
+ *
24
+ * Distinct from `data-mulmo-path` (which points at a leaf editable text). This attribute is
25
+ * used by editor UIs to wire drag-and-drop reorder.
26
+ */
27
+ export const di = (path) => (path ? ` data-mulmo-item-path="${escapeHtml(path)}"` : "");
18
28
  /** Compose a child path: `dpJoin("columns[0]", "title")` → `columns[0].title`. */
19
29
  export const dpJoin = (base, segment) => (base ? `${base}.${segment}` : segment);
20
30
  /** Escape HTML and convert newlines to <br> */
@@ -151,9 +161,9 @@ export const iconSquare = (icon, colorKey) => {
151
161
  <span class="text-2xl font-mono font-bold text-${c(colorKey)}">${escapeHtml(icon)}</span>
152
162
  </div>`;
153
163
  };
154
- /** Render a card wrapper with accent top bar */
155
- export const cardWrap = (accentColor, innerHtml, extraClass) => {
156
- return `<div class="bg-d-card rounded-lg shadow-lg overflow-hidden flex flex-col min-h-0 ${sanitizeCssClass(extraClass || "")}">
164
+ /** Render a card wrapper with accent top bar. Pass `itemPath` to emit a drag-reorder anchor. */
165
+ export const cardWrap = (accentColor, innerHtml, extraClass, itemPath) => {
166
+ return `<div class="bg-d-card rounded-lg shadow-lg overflow-hidden flex flex-col min-h-0 ${sanitizeCssClass(extraClass || "")}"${itemPath ? ` data-mulmo-item-path="${escapeHtml(itemPath)}"` : ""}>
157
167
  ${accentBar(accentColor)}
158
168
  <div class="p-5 flex flex-col flex-1 min-h-0 overflow-hidden">
159
169
  ${innerHtml}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mulmocast/deck",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "MulmoCast deck DSL: JSON-described semantic slide layouts (stats, comparison, timeline, ...) rendered to Tailwind-based HTML",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",