mechanica 2.0.0-alpha.13 → 2.0.0-alpha.14

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.
@@ -2683,6 +2683,19 @@ function createContentBlock(block) {
2683
2683
  return content;
2684
2684
  }
2685
2685
  /**
2686
+ * Whether `folder` (null = root) is the same as, or nested under, `scope` —
2687
+ * the shared folder-restriction match used by the palette (`blockAvailableIn`)
2688
+ * and the Data dialog (`dataEntryAvailableIn`). Prefix-based, so `'docs'` covers
2689
+ * `docs/guides` but not `docs-v2`; leading/trailing slashes are ignored on both
2690
+ * sides.
2691
+ */
2692
+ function isUnderFolder(folder, scope) {
2693
+ if (folder == null) return false;
2694
+ const normalizedFolder = folder.replace(/^\/+|\/+$/g, "");
2695
+ const normalizedScope = scope.replace(/^\/+|\/+$/g, "");
2696
+ return normalizedFolder === normalizedScope || normalizedFolder.startsWith(normalizedScope + "/");
2697
+ }
2698
+ /**
2686
2699
  * Whether the palette offers a block on a page in `folder` (null = root).
2687
2700
  * A block without `folders` is offered everywhere; with `folders` it is
2688
2701
  * offered only under those folders (nested folders match by prefix, so
@@ -2691,12 +2704,7 @@ function createContentBlock(block) {
2691
2704
  */
2692
2705
  function blockAvailableIn(block, folder) {
2693
2706
  if (!block.folders || block.folders.length === 0) return true;
2694
- if (folder == null) return false;
2695
- const normalizedFolder = folder.replace(/^\/+|\/+$/g, "");
2696
- return block.folders.some((entry) => {
2697
- const scope = entry.replace(/^\/+|\/+$/g, "");
2698
- return normalizedFolder === scope || normalizedFolder.startsWith(scope + "/");
2699
- });
2707
+ return block.folders.some((entry) => isUnderFolder(folder, entry));
2700
2708
  }
2701
2709
  /**
2702
2710
  * Whether the palette offers a block on a page using `layout` (the *effective*
@@ -3304,4 +3312,4 @@ function createSaveQueue(options) {
3304
3312
  };
3305
3313
  }
3306
3314
  //#endregion
3307
- export { VSegmented_default as A, relocateBlock as C, registerRichTextWidgets as D, registerBuiltinFieldEditors as E, pageThumbUrl as F, pathFromName as I, VSelect_default as L, fetchPages as M, filterPages as N, contextMenuKey as O, groupPagesByFolder as P, VPopover_default as R, placeBlock as S, uid$1 as T, ensureSlotList as _, SchemaForm_default as a, findParentSlot as b, shortcutChar as c, compareBlocks as d, createContentBlock as f, duplicateBlock as g, cloneBlock as h, normalizeTemplate as i, SmartLinkField_default as j, createContextMenu as k, blockAvailableForLayout as l, humanize as m, createSaveQueue as n, SchemaField_default as o, toBlockMeta as p, createRootFrame as r, FieldControl_default as s, SaveConflictError as t, blockAvailableIn as u, findBlock as v, removeBlock as w, moveBlock as x, findParentList as y };
3315
+ export { createContextMenu as A, placeBlock as C, registerBuiltinFieldEditors as D, uid$1 as E, groupPagesByFolder as F, pageThumbUrl as I, pathFromName as L, SmartLinkField_default as M, fetchPages as N, registerRichTextWidgets as O, filterPages as P, VSelect_default as R, moveBlock as S, removeBlock as T, duplicateBlock as _, SchemaForm_default as a, findParentList as b, shortcutChar as c, compareBlocks as d, createContentBlock as f, cloneBlock as g, humanize as h, normalizeTemplate as i, VSegmented_default as j, contextMenuKey as k, blockAvailableForLayout as l, toBlockMeta as m, createSaveQueue as n, SchemaField_default as o, isUnderFolder as p, createRootFrame as r, FieldControl_default as s, SaveConflictError as t, blockAvailableIn as u, ensureSlotList as v, relocateBlock as w, findParentSlot as x, findBlock as y, VPopover_default as z };
@@ -19,6 +19,7 @@ function getDataEntries() {
19
19
  id: entry.id,
20
20
  title: entry.title,
21
21
  props: unfoldSchema(entry.props),
22
+ ...entry.folder ? { folder: entry.folder } : {},
22
23
  ...entry.localized ? { localized: true } : {}
23
24
  }));
24
25
  }
package/dist/composer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import './editor.css';
2
2
  import { a as renderBlocks, l as ANCHOR_H, t as createMechanica, u as ANCHOR_V } from "./chunks/create-mechanica-Bz6NTRTB.js";
3
- import { C as relocateBlock, E as registerBuiltinFieldEditors, L as VSelect_default, R as VPopover_default, S as placeBlock, T as uid, _ as ensureSlotList, b as findParentSlot, c as shortcutChar, g as duplicateBlock, h as cloneBlock, i as normalizeTemplate, j as SmartLinkField_default, m as humanize, n as createSaveQueue, o as SchemaField_default, p as toBlockMeta, s as FieldControl_default, t as SaveConflictError, v as findBlock, w as removeBlock, x as moveBlock, y as findParentList } from "./chunks/editor-DSSJlkvU.js";
3
+ import { C as placeBlock, D as registerBuiltinFieldEditors, E as uid, M as SmartLinkField_default, R as VSelect_default, S as moveBlock, T as removeBlock, _ as duplicateBlock, b as findParentList, c as shortcutChar, g as cloneBlock, h as humanize, i as normalizeTemplate, m as toBlockMeta, n as createSaveQueue, o as SchemaField_default, s as FieldControl_default, t as SaveConflictError, v as ensureSlotList, w as relocateBlock, x as findParentSlot, y as findBlock, z as VPopover_default } from "./chunks/editor-BVrIfLu9.js";
4
4
  import { d as _plugin_vue_export_helper_default, l as VIcon_default, u as contents } from "./chunks/ImagePickerDialog-6skSAzJh.js";
5
5
  import { Fragment, Teleport, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onScopeDispose, openBlock, provide, reactive, ref, renderList, renderSlot, resolveComponent, toDisplayString, unref, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
6
6
  import { buildPreviewData, getDefaultValue, isBinding, lookupBinding, registerFieldSchemas, resolveBindings, walkTree } from "mechanica-shared";
package/dist/editor.css CHANGED
@@ -4386,12 +4386,12 @@ from {
4386
4386
  }
4387
4387
  .is-active .mech-page-setup__choice-default[data-v-aae1d6ee] {
4388
4388
  color: var(--mech-accent);
4389
- }.mech-data[data-v-7036fa1f] {
4389
+ }.mech-data[data-v-751371d0] {
4390
4390
  display: flex;
4391
4391
  gap: 20px;
4392
4392
  min-height: 320px;
4393
4393
  }
4394
- .mech-data__rail[data-v-7036fa1f] {
4394
+ .mech-data__rail[data-v-751371d0] {
4395
4395
  flex: none;
4396
4396
  width: 178px;
4397
4397
  display: flex;
@@ -4400,7 +4400,7 @@ from {
4400
4400
  padding-right: 14px;
4401
4401
  border-right: 1px solid var(--mech-border);
4402
4402
  }
4403
- .mech-data__entry[data-v-7036fa1f] {
4403
+ .mech-data__entry[data-v-751371d0] {
4404
4404
  display: flex;
4405
4405
  align-items: center;
4406
4406
  justify-content: space-between;
@@ -4416,49 +4416,49 @@ from {
4416
4416
  color: var(--mech-fg-alt);
4417
4417
  transition: background 0.12s, color 0.12s;
4418
4418
  }
4419
- .mech-data__entry[data-v-7036fa1f]:hover {
4419
+ .mech-data__entry[data-v-751371d0]:hover {
4420
4420
  background: var(--mech-hover);
4421
4421
  }
4422
- .mech-data__entry.is-active[data-v-7036fa1f] {
4422
+ .mech-data__entry.is-active[data-v-751371d0] {
4423
4423
  background: var(--mech-accent-soft);
4424
4424
  color: var(--mech-fg);
4425
4425
  }
4426
- .mech-data__entry-icon[data-v-7036fa1f] {
4426
+ .mech-data__entry-icon[data-v-751371d0] {
4427
4427
  flex: none;
4428
4428
  width: 14px;
4429
4429
  height: 14px;
4430
4430
  color: var(--mech-muted);
4431
4431
  }
4432
- .is-active .mech-data__entry-icon[data-v-7036fa1f] {
4432
+ .is-active .mech-data__entry-icon[data-v-751371d0] {
4433
4433
  color: var(--mech-accent);
4434
4434
  }
4435
- .mech-data__entry--setup[data-v-7036fa1f] {
4435
+ .mech-data__entry--setup[data-v-751371d0] {
4436
4436
  justify-content: flex-start;
4437
4437
  }
4438
- .mech-data__divider[data-v-7036fa1f] {
4438
+ .mech-data__divider[data-v-751371d0] {
4439
4439
  height: 1px;
4440
4440
  margin: 6px 2px;
4441
4441
  background: var(--mech-border);
4442
4442
  }
4443
- .mech-data__entry-name[data-v-7036fa1f] {
4443
+ .mech-data__entry-name[data-v-751371d0] {
4444
4444
  font-size: 13px;
4445
4445
  font-weight: 500;
4446
4446
  overflow: hidden;
4447
4447
  text-overflow: ellipsis;
4448
4448
  white-space: nowrap;
4449
4449
  }
4450
- .mech-data__entry-i18n[data-v-7036fa1f] {
4450
+ .mech-data__entry-i18n[data-v-751371d0] {
4451
4451
  flex: none;
4452
4452
  display: inline-flex;
4453
4453
  align-items: center;
4454
4454
  margin-left: auto;
4455
4455
  color: var(--mech-muted);
4456
4456
  }
4457
- .mech-data__entry-i18n .vicon[data-v-7036fa1f] {
4457
+ .mech-data__entry-i18n .vicon[data-v-751371d0] {
4458
4458
  width: 12px;
4459
4459
  height: 12px;
4460
4460
  }
4461
- .mech-data__entry-scope[data-v-7036fa1f] {
4461
+ .mech-data__entry-scope[data-v-751371d0] {
4462
4462
  flex: none;
4463
4463
  font-size: 9.5px;
4464
4464
  font-weight: 700;
@@ -4466,57 +4466,57 @@ from {
4466
4466
  text-transform: uppercase;
4467
4467
  color: var(--mech-muted);
4468
4468
  }
4469
- .mech-data__entry-i18n + .mech-data__entry-scope[data-v-7036fa1f] {
4469
+ .mech-data__entry-i18n + .mech-data__entry-scope[data-v-751371d0] {
4470
4470
  margin-left: 6px;
4471
4471
  }
4472
- .mech-data__entry-scope.is-page[data-v-7036fa1f] {
4472
+ .mech-data__entry-scope.is-page[data-v-751371d0] {
4473
4473
  color: var(--mech-accent);
4474
4474
  }
4475
- .mech-data__pane[data-v-7036fa1f] {
4475
+ .mech-data__pane[data-v-751371d0] {
4476
4476
  flex: 1;
4477
4477
  min-width: 0;
4478
4478
  display: flex;
4479
4479
  flex-direction: column;
4480
4480
  gap: 14px;
4481
4481
  }
4482
- .mech-data__head[data-v-7036fa1f] {
4482
+ .mech-data__head[data-v-751371d0] {
4483
4483
  display: flex;
4484
4484
  align-items: center;
4485
4485
  justify-content: space-between;
4486
4486
  gap: 12px;
4487
4487
  }
4488
- .mech-data__title[data-v-7036fa1f] {
4488
+ .mech-data__title[data-v-751371d0] {
4489
4489
  margin: 0;
4490
4490
  font-size: 15px;
4491
4491
  font-weight: 600;
4492
4492
  }
4493
- .mech-data__note[data-v-7036fa1f] {
4493
+ .mech-data__note[data-v-751371d0] {
4494
4494
  margin: 0;
4495
4495
  font-size: 12.5px;
4496
4496
  color: var(--mech-muted);
4497
4497
  }
4498
- .mech-data__note strong[data-v-7036fa1f] {
4498
+ .mech-data__note strong[data-v-751371d0] {
4499
4499
  font-weight: 600;
4500
4500
  color: var(--mech-fg-alt);
4501
4501
  }
4502
- .mech-data__note.is-warn[data-v-7036fa1f] {
4502
+ .mech-data__note.is-warn[data-v-751371d0] {
4503
4503
  padding: 9px 12px;
4504
4504
  border-radius: var(--mech-radius-sm);
4505
4505
  background: #fdf4e7;
4506
4506
  color: #92580e;
4507
4507
  border: 1px solid #f4d9a8;
4508
4508
  }
4509
- .mech-data__note.is-warn strong[data-v-7036fa1f] {
4509
+ .mech-data__note.is-warn strong[data-v-751371d0] {
4510
4510
  color: #7a4708;
4511
4511
  }
4512
- .mech-data__note--i18n[data-v-7036fa1f] {
4512
+ .mech-data__note--i18n[data-v-751371d0] {
4513
4513
  display: flex;
4514
4514
  align-items: center;
4515
4515
  gap: 6px;
4516
4516
  margin-top: -6px;
4517
4517
  color: var(--mech-accent);
4518
4518
  }
4519
- .mech-data__note--i18n .vicon[data-v-7036fa1f] {
4519
+ .mech-data__note--i18n .vicon[data-v-751371d0] {
4520
4520
  flex: none;
4521
4521
  width: 13px;
4522
4522
  height: 13px;
package/dist/editor.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import './editor.css';
2
2
  import { _ as mechanicaKey, a as renderBlocks, c as registerElements, i as createComposedComponent, m as createRouter, n as pushStateUpdate, r as runtimeLayoutNames } from "./chunks/create-mechanica-Bz6NTRTB.js";
3
- import { i as getDataEntries, t as buildPreviewContent } from "./chunks/preview-D4RpZ8M9.js";
4
- import { A as VSegmented_default, C as relocateBlock, D as registerRichTextWidgets, E as registerBuiltinFieldEditors, F as pageThumbUrl, I as pathFromName, L as VSelect_default, M as fetchPages, N as filterPages, O as contextMenuKey, P as groupPagesByFolder, R as VPopover_default, S as placeBlock, T as uid, a as SchemaForm_default, b as findParentSlot, c as shortcutChar, d as compareBlocks, f as createContentBlock, g as duplicateBlock, h as cloneBlock, k as createContextMenu, l as blockAvailableForLayout, m as humanize, n as createSaveQueue, p as toBlockMeta, r as createRootFrame, t as SaveConflictError, u as blockAvailableIn, v as findBlock, w as removeBlock, x as moveBlock } from "./chunks/editor-DSSJlkvU.js";
3
+ import { i as getDataEntries, t as buildPreviewContent } from "./chunks/preview-izKRqfM-.js";
4
+ import { A as createContextMenu, C as placeBlock, D as registerBuiltinFieldEditors, E as uid, F as groupPagesByFolder, I as pageThumbUrl, L as pathFromName, N as fetchPages, O as registerRichTextWidgets, P as filterPages, R as VSelect_default, S as moveBlock, T as removeBlock, _ as duplicateBlock, a as SchemaForm_default, c as shortcutChar, d as compareBlocks, f as createContentBlock, g as cloneBlock, h as humanize, j as VSegmented_default, k as contextMenuKey, l as blockAvailableForLayout, m as toBlockMeta, n as createSaveQueue, p as isUnderFolder, r as createRootFrame, t as SaveConflictError, u as blockAvailableIn, w as relocateBlock, x as findParentSlot, y as findBlock, z as VPopover_default } from "./chunks/editor-BVrIfLu9.js";
5
5
  import { c as useDialog, d as _plugin_vue_export_helper_default, l as VIcon_default, n as VDialog_default, o as createDialogStore, s as dialogKey } from "./chunks/ImagePickerDialog-6skSAzJh.js";
6
6
  import { Fragment, Teleport, Transition, TransitionGroup, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, markRaw, mergeProps, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onErrorCaptured, onMounted, onScopeDispose, openBlock, provide, reactive, ref, renderList, resolveComponent, resolveDynamicComponent, shallowRef, toDisplayString, unref, useTemplateRef, vModelCheckbox, vModelText, watch, withCtx, withDirectives, withModifiers } from "vue";
7
7
  import { getDefaultValue, localeLabel, localePath, parseLocalePath, registerFieldSchemas } from "mechanica-shared";
@@ -305,12 +305,18 @@ function rectOf(id) {
305
305
  function useBlockFrames(store, options = {}) {
306
306
  const hovered = ref(null);
307
307
  const selected = ref(null);
308
+ const active = () => options.enabled?.() ?? true;
308
309
  const onMove = (event) => {
310
+ if (!active()) {
311
+ if (store.hoverId) store.setHover(null);
312
+ return;
313
+ }
309
314
  const target = event.target;
310
315
  if (isEditorUI(target)) return;
311
316
  store.setHover(findBlockId(target));
312
317
  };
313
318
  const onClick = (event) => {
319
+ if (!active()) return;
314
320
  const target = event.target;
315
321
  if (isEditorUI(target)) return;
316
322
  const link = findLink(target);
@@ -605,6 +611,19 @@ function resolveShortcut(event) {
605
611
  return null;
606
612
  }
607
613
  //#endregion
614
+ //#region src/editor/lib/data-meta.ts
615
+ /**
616
+ * Whether the editor's Data dialog offers a `defineData` entry on a page in
617
+ * `folder` (null = root). An entry without `folder` is offered everywhere; with
618
+ * `folder` it is offered only under that folder (nested folders match by prefix,
619
+ * so `'examples'` covers `examples/advanced` too). This only filters what the
620
+ * dialog *draws* — the value's scope and where it is stored are unaffected.
621
+ */
622
+ function dataEntryAvailableIn(entry, folder) {
623
+ if (!entry.folder) return true;
624
+ return isUnderFolder(folder, entry.folder);
625
+ }
626
+ //#endregion
608
627
  //#region src/editor/lib/navigation.ts
609
628
  var navigationKey = Symbol("mech-navigation");
610
629
  /** Hard-navigation fallback for contexts without the in-place switcher. */
@@ -954,8 +973,9 @@ var DataSettings_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
954
973
  const localeConfig = window.state?.locales ?? null;
955
974
  const localeName = (code) => code ? localeLabel(localeConfig, code) : "";
956
975
  const hasPageSetup = runtimeLayoutNames().length > 1 || store.blocks.some((block) => block.standalone && !block.hidden);
957
- const activeId = ref(store.dataEntries[0]?.id ?? (hasPageSetup ? PAGE_SETUP : null));
958
- const active = computed(() => activeId.value === PAGE_SETUP ? null : store.dataEntries.find((entry) => entry.id === activeId.value) ?? store.dataEntries[0] ?? null);
976
+ const entries = computed(() => store.dataEntries.filter((entry) => dataEntryAvailableIn(entry, store.folder)));
977
+ const activeId = ref(entries.value[0]?.id ?? (hasPageSetup ? PAGE_SETUP : null));
978
+ const active = computed(() => activeId.value === PAGE_SETUP ? null : entries.value.find((entry) => entry.id === activeId.value) ?? entries.value[0] ?? null);
959
979
  const currentScope = computed(() => active.value ? store.scopeOf(active.value.id) : "page");
960
980
  const scopeOptions = computed(() => [
961
981
  {
@@ -986,7 +1006,7 @@ var DataSettings_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
986
1006
  }, [createVNode(VIcon_default, {
987
1007
  name: "frame",
988
1008
  class: "mech-data__entry-icon"
989
- }), _cache[2] || (_cache[2] = createElementVNode("span", { class: "mech-data__entry-name" }, "Page setup", -1))], 2), unref(store).dataEntries.length ? (openBlock(), createElementBlock("div", _hoisted_3$10)) : createCommentVNode("", true)], 64)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(unref(store).dataEntries, (entry) => {
1009
+ }), _cache[2] || (_cache[2] = createElementVNode("span", { class: "mech-data__entry-name" }, "Page setup", -1))], 2), entries.value.length ? (openBlock(), createElementBlock("div", _hoisted_3$10)) : createCommentVNode("", true)], 64)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(entries.value, (entry) => {
990
1010
  return openBlock(), createElementBlock("button", {
991
1011
  key: entry.id,
992
1012
  type: "button",
@@ -1018,7 +1038,7 @@ var DataSettings_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
1018
1038
  ])) : (openBlock(), createElementBlock("p", _hoisted_12$2, "This page has no editable data."))]);
1019
1039
  };
1020
1040
  }
1021
- }), [["__scopeId", "data-v-7036fa1f"]]);
1041
+ }), [["__scopeId", "data-v-751371d0"]]);
1022
1042
  //#endregion
1023
1043
  //#region src/editor/dialogs/DataDialog.vue
1024
1044
  var DataDialog_default = /* @__PURE__ */ defineComponent({
@@ -2949,7 +2969,7 @@ var EditorApp_default = /* @__PURE__ */ defineComponent({
2949
2969
  const dialog = createDialogStore();
2950
2970
  provide(dialogKey, dialog);
2951
2971
  const openData = () => dialog.open(DataDialog_default);
2952
- const hasPageDialog = computed(() => store.dataEntries.length > 0 || runtimeLayoutNames().length > 1 || store.blocks.some((block) => block.standalone && !block.hidden));
2972
+ const hasPageDialog = computed(() => store.dataEntries.some((entry) => dataEntryAvailableIn(entry, store.folder)) || runtimeLayoutNames().length > 1 || store.blocks.some((block) => block.standalone && !block.hidden));
2953
2973
  const navigation = props.navigation ?? fallbackNavigation();
2954
2974
  provide(navigationKey, navigation);
2955
2975
  provide(contextMenuKey, createContextMenu());
@@ -3024,7 +3044,10 @@ var EditorApp_default = /* @__PURE__ */ defineComponent({
3024
3044
  }
3025
3045
  }
3026
3046
  const collapsed = ref(false);
3027
- const { hovered, selected } = useBlockFrames(store, { followLink: (path) => void navigation.switchPage(path) });
3047
+ const { hovered, selected } = useBlockFrames(store, {
3048
+ followLink: (path) => void navigation.switchPage(path),
3049
+ enabled: () => !collapsed.value
3050
+ });
3028
3051
  const selectedName = computed(() => store.selected ? store.blocksById.get(store.selected.blockId)?.name : "");
3029
3052
  const selectedComposed = computed(() => !!store.selected && store.blocksById.get(store.selected.blockId)?.composed === true);
3030
3053
  function editInComposer() {
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { _ as mechanicaKey, a as renderBlocks, c as registerElements, d as Link, f as loadBlocks, g as useRouter, h as useRoute, i as createComposedComponent, m as createRouter, o as elements, p as usedBlockIds, s as isElementBlock, t as createMechanica } from "./chunks/create-mechanica-Bz6NTRTB.js";
2
- import { a as registerDataEntry, i as getDataEntries, n as mountPreviewApp, r as clearDataEntries, t as buildPreviewContent } from "./chunks/preview-D4RpZ8M9.js";
2
+ import { a as registerDataEntry, i as getDataEntries, n as mountPreviewApp, r as clearDataEntries, t as buildPreviewContent } from "./chunks/preview-izKRqfM-.js";
3
3
  import { computed, createApp, createSSRApp, defineComponent, h, inject, isReactive, onMounted, onServerPrefetch, reactive, ref, shallowReactive } from "vue";
4
4
  import { localePath, normalizeClassManifest, passDefaultValue } from "mechanica-shared";
5
5
  import { unfoldSchema } from "compact-json-schema";
@@ -3,6 +3,8 @@ export interface DataEntryInput {
3
3
  id: string;
4
4
  title?: string;
5
5
  props: unknown;
6
+ /** Restrict the entry to pages under this folder (nested folders match by prefix). */
7
+ folder?: string;
6
8
  /** Translate this entry's site/folder value per locale (multi-language sites). */
7
9
  localized?: boolean;
8
10
  }
@@ -6,6 +6,14 @@ export interface DataDefinition<Id extends string, T extends SchemaItem> {
6
6
  title?: string;
7
7
  /** Data shape (compact-json-schema). */
8
8
  props: T;
9
+ /**
10
+ * Restrict the entry to pages under this folder (a folder path relative to
11
+ * `pages/`, e.g. `'examples'`; nested folders match by prefix). Omitted =
12
+ * offered everywhere. This only filters where the editor's Data dialog offers
13
+ * the entry — the value's scope (site / folder / page, chosen per page) and
14
+ * where it is stored are unchanged.
15
+ */
16
+ folder?: string;
9
17
  /**
10
18
  * Store this entry's site/folder value per locale on a multi-language site
11
19
  * (with fallback to the default locale), so shared strings can be translated.
@@ -21,6 +21,14 @@ export declare function composedBlockMeta(def: ComposedBlockDefinition): Block;
21
21
  export declare function compareBlocks(a: Block, b: Block): number;
22
22
  /** Create a fresh placed block with schema defaults for its data. */
23
23
  export declare function createContentBlock(block: Block): ContentBlock;
24
+ /**
25
+ * Whether `folder` (null = root) is the same as, or nested under, `scope` —
26
+ * the shared folder-restriction match used by the palette (`blockAvailableIn`)
27
+ * and the Data dialog (`dataEntryAvailableIn`). Prefix-based, so `'docs'` covers
28
+ * `docs/guides` but not `docs-v2`; leading/trailing slashes are ignored on both
29
+ * sides.
30
+ */
31
+ export declare function isUnderFolder(folder: string | null, scope: string): boolean;
24
32
  /**
25
33
  * Whether the palette offers a block on a page in `folder` (null = root).
26
34
  * A block without `folders` is offered everywhere; with `folders` it is
@@ -0,0 +1,9 @@
1
+ import type { DataEntry } from 'mechanica-shared';
2
+ /**
3
+ * Whether the editor's Data dialog offers a `defineData` entry on a page in
4
+ * `folder` (null = root). An entry without `folder` is offered everywhere; with
5
+ * `folder` it is offered only under that folder (nested folders match by prefix,
6
+ * so `'examples'` covers `examples/advanced` too). This only filters what the
7
+ * dialog *draws* — the value's scope and where it is stored are unaffected.
8
+ */
9
+ export declare function dataEntryAvailableIn(entry: DataEntry, folder: string | null): boolean;
@@ -23,6 +23,15 @@ export declare function linkClickAction(link: HTMLAnchorElement, event: Pick<Mou
23
23
  export interface BlockFramesOptions {
24
24
  /** Follow an internal page link clicked on the live page (in-place switch). */
25
25
  followLink?: (path: string) => void;
26
+ /**
27
+ * Whether the editor overlay is active. When this returns `false` (the panels
28
+ * are collapsed), the overlay stops touching the live page entirely — it no
29
+ * longer hovers or selects blocks, and clicks on buttons, links and every
30
+ * other control behave natively, so the page is usable like the published
31
+ * site. `true`/absent keeps the editing behavior (block selection, links
32
+ * followed in place).
33
+ */
34
+ enabled?: () => boolean;
26
35
  }
27
36
  /**
28
37
  * Track hover/selection frames over the live page. Hover is shared state on the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mechanica",
3
- "version": "2.0.0-alpha.13",
3
+ "version": "2.0.0-alpha.14",
4
4
  "description": "Build Vue 3 websites with a visual block editor",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -60,7 +60,7 @@
60
60
  "prepublishOnly": "bun run build"
61
61
  },
62
62
  "dependencies": {
63
- "mechanica-shared": "2.0.0-alpha.13",
63
+ "mechanica-shared": "2.0.0-alpha.14",
64
64
  "@vue/compiler-sfc": "^3.5.38",
65
65
  "compact-json-schema": "^0.1.5",
66
66
  "estree-walker": "^3.0.3",