rimecms 1.0.0 → 1.1.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.
Files changed (174) hide show
  1. package/dist/adapter-sqlite/generate-schema/templates.server.d.ts +9 -9
  2. package/dist/adapter-sqlite/generate-schema/templates.server.js +9 -9
  3. package/dist/adapter-sqlite/paths.server.js +24 -15
  4. package/dist/adapter-sqlite/rows.server.d.ts +1 -1
  5. package/dist/core/adapter.d.ts +8 -4
  6. package/dist/core/boot.server.d.ts +2 -2
  7. package/dist/core/config/context.server.d.ts +2 -2
  8. package/dist/core/dev/codegen/routes/common.server.d.ts +2 -0
  9. package/dist/core/dev/codegen/routes/common.server.js +7 -3
  10. package/dist/core/dev/codegen/routes/util.server.d.ts +2 -1
  11. package/dist/core/dev/codegen/routes/util.server.js +4 -1
  12. package/dist/core/dev/config-memo.server.js +4 -0
  13. package/dist/core/i18n/en/fields.d.ts +1 -1
  14. package/dist/core/i18n/en/fields.js +1 -1
  15. package/dist/core/i18n/fr/fields.d.ts +1 -1
  16. package/dist/core/i18n/fr/fields.js +1 -1
  17. package/dist/core/prototype/collection/operations/duplicate.js +1 -1
  18. package/dist/core/prototype/collection/thumbnail/hooks/set-document-thumbnail.server.js +1 -1
  19. package/dist/core/prototype/shared/title/hooks/set-document-title.server.js +1 -1
  20. package/dist/core/prototype/shared/url/addresses.server.d.ts +10 -0
  21. package/dist/core/prototype/shared/url/addresses.server.js +17 -17
  22. package/dist/core/prototype/shared/url/hooks/detach-paths.server.d.ts +3 -2
  23. package/dist/core/prototype/shared/url/hooks/detach-paths.server.js +9 -8
  24. package/dist/core/prototype/shared/url/hooks/sync-paths.server.d.ts +3 -2
  25. package/dist/core/prototype/shared/url/hooks/sync-paths.server.js +5 -4
  26. package/dist/fields/blocks/component/AddBlockButton.svelte +1 -1
  27. package/dist/fields/blocks/component/Block.svelte +4 -5
  28. package/dist/fields/blocks/component/Blocks.svelte +17 -13
  29. package/dist/fields/blocks/component/focus/BlocksFocus.svelte +53 -65
  30. package/dist/fields/blocks/component/focus/DefaultRender.svelte +108 -0
  31. package/dist/fields/blocks/component/focus/{RenderPlaceholder.svelte.d.ts → DefaultRender.svelte.d.ts} +3 -3
  32. package/dist/fields/blocks/component/focus/Inspector.svelte +160 -0
  33. package/dist/fields/blocks/component/focus/Inspector.svelte.d.ts +7 -0
  34. package/dist/fields/blocks/component/focus/Layers.svelte +16 -3
  35. package/dist/fields/blocks/component/focus/LayersList.svelte +28 -11
  36. package/dist/fields/blocks/component/focus/LayersList.svelte.d.ts +2 -0
  37. package/dist/fields/blocks/component/focus/Palette.svelte +3 -3
  38. package/dist/fields/blocks/component/focus/Renders.svelte +66 -15
  39. package/dist/fields/blocks/component/focus/Renders.svelte.d.ts +5 -1
  40. package/dist/fields/blocks/component/focus/StagePlaceholder.svelte +1 -4
  41. package/dist/fields/blocks/component/focus/focus.svelte.d.ts +26 -12
  42. package/dist/fields/blocks/component/focus/focus.svelte.js +114 -57
  43. package/dist/fields/blocks/component/picker/BlockTile.svelte +3 -5
  44. package/dist/fields/combobox/component/ComboBox.svelte +1 -1
  45. package/dist/fields/combobox/component/combobox.css +1 -1
  46. package/dist/fields/date/component/Date.svelte +1 -1
  47. package/dist/fields/group/component/Group.svelte +4 -4
  48. package/dist/fields/link/component/Link.svelte +1 -1
  49. package/dist/fields/link/component/RessourceInput.svelte +2 -2
  50. package/dist/fields/link/index.d.ts +1 -1
  51. package/dist/fields/number/component/Number.svelte +1 -1
  52. package/dist/fields/relation/component/Cell.svelte +3 -1
  53. package/dist/fields/relation/component/RelationInline.svelte +51 -20
  54. package/dist/fields/relation/component/default/Default.svelte +3 -3
  55. package/dist/fields/relation/component/upload/Browse.svelte +2 -2
  56. package/dist/fields/relation/component/upload/Upload.svelte +2 -2
  57. package/dist/fields/relation/index.d.ts +1 -41
  58. package/dist/fields/relation/index.js +0 -67
  59. package/dist/fields/relation/util.d.ts +69 -0
  60. package/dist/fields/relation/util.js +103 -0
  61. package/dist/fields/rich-text/client.d.ts +2 -5
  62. package/dist/fields/rich-text/client.js +1 -3
  63. package/dist/fields/rich-text/component/Cell.svelte +1 -1
  64. package/dist/fields/rich-text/component/bubble-menu/bubble-menu.css +1 -1
  65. package/dist/fields/rich-text/component/bubble-menu/node-selector/node-selector.css +1 -1
  66. package/dist/fields/rich-text/core/features/link/component/link-selector.svelte +2 -2
  67. package/dist/fields/rich-text/core/features/resource/resource-extension.js +3 -3
  68. package/dist/fields/rich-text/core/features/resource/resource.svelte +2 -2
  69. package/dist/fields/rich-text/core/features/upload/upload-extension.js +3 -4
  70. package/dist/fields/rich-text/core/features/upload/upload.svelte +2 -2
  71. package/dist/fields/rich-text/index.d.ts +0 -17
  72. package/dist/fields/rich-text/index.js +0 -44
  73. package/dist/fields/rich-text/json.d.ts +18 -0
  74. package/dist/fields/rich-text/json.js +44 -0
  75. package/dist/fields/select/component/Select.svelte +2 -2
  76. package/dist/fields/text/component/TextInline.svelte +113 -0
  77. package/dist/fields/text/component/TextInline.svelte.d.ts +14 -0
  78. package/dist/fields/textarea/component/TextArea.svelte +1 -1
  79. package/dist/fields/tree/component/TreeBlock.svelte +4 -4
  80. package/dist/index.d.ts +2 -9
  81. package/dist/index.js +3 -8
  82. package/dist/{panel/components/sections/live → live}/Consumer.svelte +2 -2
  83. package/dist/{panel/components/sections/live → live}/Consumer.svelte.d.ts +1 -1
  84. package/dist/{panel/components/sections/live → live}/LiveEdit.svelte +2 -2
  85. package/dist/{panel/components/sections/live → live}/Provider.svelte +1 -1
  86. package/dist/{panel/context/live.svelte.d.ts → live/context.svelte.d.ts} +1 -1
  87. package/dist/{panel/context/live.svelte.js → live/context.svelte.js} +3 -3
  88. package/dist/panel/components/fields/Error.svelte +1 -1
  89. package/dist/panel/components/fields/FieldsPreview.svelte +1 -1
  90. package/dist/panel/components/fields/FieldsPreviewTrigger.svelte +1 -1
  91. package/dist/panel/components/fields/Hint.svelte +1 -1
  92. package/dist/panel/components/fields/setting.css +6 -6
  93. package/dist/panel/components/sections/auth/AuthForm.svelte +2 -2
  94. package/dist/panel/components/sections/collection/Avatar.svelte +1 -1
  95. package/dist/panel/components/sections/collection/bulk-upload/FileDrop.svelte +1 -1
  96. package/dist/panel/components/sections/collection/bulk-upload/PageDrop.svelte +3 -3
  97. package/dist/panel/components/sections/collection/bulk-upload/UploadProgress.svelte +1 -1
  98. package/dist/panel/components/sections/collection/folder/Folder.svelte +1 -1
  99. package/dist/panel/components/sections/collection/folder/FolderWithActions.svelte +2 -2
  100. package/dist/panel/components/sections/collection/grid/grid-item/GridItem.svelte +1 -1
  101. package/dist/panel/components/sections/collection/header/DisplayMode.svelte +1 -2
  102. package/dist/panel/components/sections/collection/list/CollectionList.svelte +2 -2
  103. package/dist/panel/components/sections/collection/list/header/Header.svelte +1 -1
  104. package/dist/panel/components/sections/collection/list/row/Row.svelte +1 -1
  105. package/dist/panel/components/sections/collection/tree/CollectionTree.svelte +1 -1
  106. package/dist/panel/components/sections/collection/tree/CollectionTreeNode.svelte +1 -1
  107. package/dist/panel/components/sections/collection/upload-thumb-cell/UploadThumbCell.svelte +1 -1
  108. package/dist/panel/components/sections/commands/CommandButton.svelte +1 -1
  109. package/dist/panel/components/sections/document/AuthAPIKeyDialog.svelte +1 -1
  110. package/dist/panel/components/sections/document/AuthFooter.svelte +2 -2
  111. package/dist/panel/components/sections/document/AutoSaveBanner.svelte +2 -2
  112. package/dist/panel/components/sections/document/ButtonStatus.svelte +1 -1
  113. package/dist/panel/components/sections/document/ChangeSlugDialog.svelte +1 -1
  114. package/dist/panel/components/sections/document/DocumentChildren.svelte +2 -2
  115. package/dist/panel/components/sections/document/upload-header/UploadHeader.svelte +2 -2
  116. package/dist/panel/components/sections/document/upload-header/drop-zone/DropZone.svelte +1 -1
  117. package/dist/panel/components/sections/document/upload-header/drop-zone/DropZone.svelte.d.ts +1 -1
  118. package/dist/panel/components/sections/live/LiveFloatingUI.svelte +2 -2
  119. package/dist/panel/components/ui/breadcrumb/BreadCrumb.svelte +1 -1
  120. package/dist/panel/components/ui/button/button.svelte +3 -4
  121. package/dist/panel/components/ui/calendar/calendar.svelte.d.ts +1 -1
  122. package/dist/panel/components/ui/card/card.svelte +2 -2
  123. package/dist/panel/components/ui/card-document/card-document.svelte +2 -2
  124. package/dist/panel/components/ui/card-resource/card-resource.svelte +2 -2
  125. package/dist/panel/components/ui/checkbox/checkbox.svelte.d.ts +1 -1
  126. package/dist/panel/components/ui/command/command-input.svelte +1 -1
  127. package/dist/panel/components/ui/context-menu/context-menu.css +1 -1
  128. package/dist/panel/components/ui/dialog/dialog-content.css +1 -1
  129. package/dist/panel/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +1 -1
  130. package/dist/panel/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +1 -1
  131. package/dist/panel/components/ui/dropdown-menu/dropdown-menu-content.css +1 -1
  132. package/dist/panel/components/ui/input/input.svelte +1 -1
  133. package/dist/panel/components/ui/nav/Nav.svelte +2 -3
  134. package/dist/panel/components/ui/nav/NavGroup.svelte +1 -1
  135. package/dist/panel/components/ui/nav/NavItemButton.svelte +1 -1
  136. package/dist/panel/components/ui/nav/UserButton.svelte +1 -1
  137. package/dist/panel/components/ui/page-header/PageHeader.svelte +1 -1
  138. package/dist/panel/components/ui/popover/popover-content.css +1 -1
  139. package/dist/panel/components/ui/radio-row-group/radio-row-group.css +0 -1
  140. package/dist/panel/components/ui/sheet/sheet.css +1 -1
  141. package/dist/panel/components/ui/sonner/sonner.css +1 -1
  142. package/dist/panel/components/ui/switch/switch.css +0 -2
  143. package/dist/panel/components/ui/switch/switch.svelte.d.ts +1 -1
  144. package/dist/panel/components/ui/tabs/tabs.css +2 -1
  145. package/dist/panel/components/ui/tag/tag.svelte +1 -1
  146. package/dist/panel/components/ui/tree/tree-rows.css +3 -3
  147. package/dist/panel/context/collection.svelte.d.ts +2 -2
  148. package/dist/panel/context/config.svelte.d.ts +2 -2
  149. package/dist/panel/context/documentForm.svelte.js +1 -1
  150. package/dist/panel/index.d.ts +3 -5
  151. package/dist/panel/index.js +4 -6
  152. package/dist/panel/pages/auth/forgot-password/ForgotPassword.svelte +1 -1
  153. package/dist/panel/pages/dashboard/Dashboard.svelte +1 -1
  154. package/dist/panel/pages/dashboard/DashboardCard.svelte +2 -2
  155. package/dist/panel/pages/dashboard/DashboardCollection.svelte +1 -1
  156. package/dist/panel/pages/dashboard/DashboardRow.svelte +1 -1
  157. package/dist/panel/public.d.ts +4 -0
  158. package/dist/panel/public.js +6 -0
  159. package/dist/panel/style/index.css +13 -37
  160. package/dist/panel/style/mixins/index.css +1 -1
  161. package/dist/panel/style/palette.css +3 -3
  162. package/dist/panel/style/scheme.css +10 -34
  163. package/dist/public.d.ts +13 -0
  164. package/dist/public.js +12 -0
  165. package/package.json +12 -6
  166. package/dist/fields/blocks/component/focus/RenderPlaceholder.svelte +0 -77
  167. package/dist/fields/blocks/component/focus/Stage.svelte +0 -190
  168. package/dist/fields/blocks/component/focus/Stage.svelte.d.ts +0 -8
  169. package/dist/fields/relation/client.d.ts +0 -28
  170. package/dist/fields/relation/client.js +0 -37
  171. /package/dist/{panel/util → fields/relation}/populate.d.ts +0 -0
  172. /package/dist/{panel/util → fields/relation}/populate.js +0 -0
  173. /package/dist/{panel/components/sections/live → live}/LiveEdit.svelte.d.ts +0 -0
  174. /package/dist/{panel/components/sections/live → live}/Provider.svelte.d.ts +0 -0
@@ -21,6 +21,16 @@
21
21
  /** The document's focus mode, absent in a nested form. */
22
22
  const focus = getBlocksFocusContext();
23
23
  const list = $derived(normalizeFieldPath(path));
24
+ /**
25
+ * Where focus opens: a list inside a block on that block, `sections.1.items` on `sections.1`;
26
+ * any other on itself.
27
+ */
28
+ const focusTarget = $derived.by(() => {
29
+ const parts = list.split('.');
30
+ const last = parts.findLastIndex((part) => /^\d+$/.test(part));
31
+ if (last === -1 || !form.blocks.builder(parts.slice(0, last).join('.'))) return list;
32
+ return parts.slice(0, last + 1).join('.');
33
+ });
24
34
  const summary = $derived(config.get.layout === 'summary' && !!focus);
25
35
 
26
36
  const field = $derived(form.useField(path, config));
@@ -119,7 +129,7 @@
119
129
  variant="ghost"
120
130
  size="sm"
121
131
  icon={Maximize2}
122
- onclick={() => focus.open(list)}
132
+ onclick={() => focus.open(focusTarget)}
123
133
  data-focus-open={list}
124
134
  >
125
135
  {t__('fields.open_editor')}
@@ -138,7 +148,7 @@
138
148
  : t__('fields.blocks_count|m|p', String(count))}
139
149
  </span>
140
150
  <Button
141
- onclick={() => focus.open(list)}
151
+ onclick={() => focus.open(focusTarget)}
142
152
  size="sm"
143
153
  variant="ghost"
144
154
  icon={Maximize2}
@@ -182,7 +192,7 @@
182
192
  <Field.Error error={field.error} />
183
193
  </fieldset>
184
194
 
185
- <style>/* A level: its fill, a hairline, its shadow. raised, float. */
195
+ <style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
186
196
 
187
197
  /* A well: an input, a track, a dropzone. Its edge shows on hover. */
188
198
 
@@ -257,7 +267,7 @@
257
267
  background-color: var(--rz-bg-raised);
258
268
  box-shadow:
259
269
  0 0 0 1px var(--rz-border),
260
- var(--rz-shadow-raised);
270
+ var(--rz-shadow-raised, 0 0 transparent);
261
271
  border-radius: var(--rz-radius-xl);
262
272
 
263
273
  :global(.rz-button) {
@@ -286,24 +296,18 @@
286
296
  background-color: var(--rz-bg-raised);
287
297
  box-shadow:
288
298
  0 0 0 1px var(--rz-border),
289
- var(--rz-shadow-raised);
299
+ var(--rz-shadow-raised, 0 0 transparent);
290
300
  }
291
301
 
292
302
  > :global(.rz-block + .rz-block) {
293
303
  border-top: 1px solid var(--rz-border);
294
304
  }
295
-
296
- /* An open block draws its own edge. */
297
- > :global(.rz-block[data-open] + .rz-block) {
298
- border-top-color: transparent;
299
- }
300
305
  }
301
306
 
302
- /* Inside a group, a block, a tree item or a stage card: a hairline, no second fill. */
307
+ /* Inside a group, a block or a tree item: a hairline, no second fill. */
303
308
  :global(.rz-group-field__content) :is(.rz-blocks__list:not([data-empty]), .rz-blocks__summary),
304
309
  :global(.rz-block__fields) :is(.rz-blocks__list:not([data-empty]), .rz-blocks__summary),
305
- :global(.rz-tree-item__fields) :is(.rz-blocks__list:not([data-empty]), .rz-blocks__summary),
306
- :global(.rz-stage__fields) :is(.rz-blocks__list:not([data-empty]), .rz-blocks__summary) {
310
+ :global(.rz-tree-item__fields) :is(.rz-blocks__list:not([data-empty]), .rz-blocks__summary) {
307
311
  background-color: transparent;
308
312
  box-shadow: 0 0 0 1px var(--rz-border);
309
313
  }
@@ -10,7 +10,7 @@
10
10
  import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
11
11
  import { getLocaleContext } from '../../../../panel/context/locale.svelte.js';
12
12
  import { getNavContext } from '../../../../panel/context/nav.svelte.js';
13
- import { populate } from '../../../../panel/util/populate.js';
13
+ import { populate } from '../../../relation/populate.js';
14
14
  import { capitalize } from '../../../../util/string.js';
15
15
  import { ChevronRight, PanelRight, ToyBrick, X } from '@lucide/svelte';
16
16
  import { untrack } from 'svelte';
@@ -19,8 +19,8 @@
19
19
  import { getBlocksFocusContext, type SidebarTab } from './focus.svelte.js';
20
20
  import Layers from './Layers.svelte';
21
21
  import Palette from './Palette.svelte';
22
+ import Inspector from './Inspector.svelte';
22
23
  import Renders from './Renders.svelte';
23
- import Stage from './Stage.svelte';
24
24
  import StagePlaceholder from './StagePlaceholder.svelte';
25
25
 
26
26
  const { form }: { form: DocumentFormContext } = $props();
@@ -30,14 +30,26 @@
30
30
  /** The overlay starts where the navigation ends, folded or not. */
31
31
  const nav = getNavContext();
32
32
 
33
- const builder = $derived(focus.path ? form.blocks.builder(focus.path) : undefined);
34
- /** The types of the list the next insert goes to: the selected block's, else the open one. */
33
+ /** The list on screen: the open one, or the one the narrowed block sits in. */
34
+ const stageList = $derived(focus.narrowedRow?.list ?? focus.path ?? '');
35
+ const builder = $derived(stageList ? form.blocks.builder(stageList) : undefined);
36
+ /** The types of the list the next insert goes to. */
35
37
  const addable = $derived.by(() => {
36
- const list = focus.current?.list ?? focus.path;
38
+ const list = focus.insertList();
37
39
  return list ? (form.blocks.builder(list)?.get.blocks ?? []) : [];
38
40
  });
39
41
  const crumbs = $derived(focus.breadcrumb());
40
- const count = $derived(focus.path ? form.blocks.list(focus.path).length : 0);
42
+ /** The open list's blocks, or those the narrowed block holds. */
43
+ const count = $derived(
44
+ focus.narrowedRow
45
+ ? focus.narrowedRow.children.reduce(
46
+ (sum, child) => sum + form.blocks.list(child.list).length,
47
+ 0
48
+ )
49
+ : focus.path
50
+ ? form.blocks.list(focus.path).length
51
+ : 0
52
+ );
41
53
  const countLabel = $derived(
42
54
  count === 1 ? t__('fields.blocks_count', '1') : t__('fields.blocks_count|m|p', String(count))
43
55
  );
@@ -57,24 +69,21 @@
57
69
  return parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
58
70
  }
59
71
 
60
- /** Fields to show: a render with nothing but fields of its own, beside the stack of renders. */
61
- const inspectable = $derived(focus.hasRenders);
62
-
63
72
  // The selection moved. Nothing left to inspect: the types to add. Picked from the layers in the
64
73
  // sheet: put it away, to see the block.
65
74
  $effect(() => {
66
75
  const picked = !!focus.current;
67
76
  untrack(() => {
68
- if (focus.tab === 'inspector' && (!picked || !inspectable)) focus.tab = 'add';
77
+ if (focus.tab === 'inspector' && !picked) focus.tab = 'add';
69
78
  if (focus.tab === 'layers') panelOpen = false;
70
79
  });
71
80
  });
72
81
 
73
82
  // Arriving on an empty list: the types to add.
74
83
  $effect(() => {
75
- const list = focus.path;
84
+ const opened = focus.path;
76
85
  untrack(() => {
77
- if (list && !focus.locked && !form.blocks.list(list).length) focus.tab = 'add';
86
+ if (opened && !focus.locked && !count) focus.tab = 'add';
78
87
  });
79
88
  });
80
89
 
@@ -82,7 +91,7 @@
82
91
  $effect(() => {
83
92
  if (!focus.inspected) return;
84
93
  untrack(() => {
85
- if (narrow && inspectable) panelOpen = true;
94
+ if (narrow) panelOpen = true;
86
95
  });
87
96
  });
88
97
 
@@ -109,10 +118,10 @@
109
118
  else focus.removeSelection();
110
119
  }
111
120
 
112
- /** Escape goes back one step: the selection, then focus mode. The sheet closes itself. */
121
+ /** Escape goes back one step: the selection, then one level up. The sheet closes itself. */
113
122
  function back() {
114
123
  if (!focus.rootSelected) focus.selectRoot();
115
- else focus.close();
124
+ else focus.up();
116
125
  }
117
126
 
118
127
  async function paste() {
@@ -130,8 +139,7 @@
130
139
  */
131
140
  useCommands(() => {
132
141
  if (!focus.path) return [];
133
- const list = focus.current?.list ?? focus.path;
134
- const types = form.blocks.builder(list)?.get.blocks ?? [];
142
+ const types = addable;
135
143
  const row = focus.currentRow;
136
144
  const editing = !focus.locked;
137
145
  const free = () => !dialogOpen();
@@ -145,7 +153,7 @@
145
153
  run: () => focus.insertType(builder.name)
146
154
  }))
147
155
  : []),
148
- ...(editing && row
156
+ ...(editing && row && !focus.isNarrowedBlock(row.path)
149
157
  ? [
150
158
  {
151
159
  id: 'blocks.duplicate',
@@ -302,7 +310,6 @@
302
310
  <div
303
311
  class="rz-blocks-focus"
304
312
  data-focus={focus.path}
305
- data-layout={focus.hasRenders ? 'renders' : 'fields'}
306
313
  style:left={nav?.width ?? '0'}
307
314
  bind:clientWidth={width}
308
315
  >
@@ -370,11 +377,9 @@
370
377
  <Tabs.Trigger value="layers" data-label={t__('fields.layers')}>
371
378
  {t__('fields.layers')}
372
379
  </Tabs.Trigger>
373
- {#if inspectable}
374
- <Tabs.Trigger value="inspector" data-label={t__('fields.inspector')}>
375
- {t__('fields.inspector')}
376
- </Tabs.Trigger>
377
- {/if}
380
+ <Tabs.Trigger value="inspector" data-label={t__('fields.inspector')}>
381
+ {t__('fields.inspector')}
382
+ </Tabs.Trigger>
378
383
  {#if !focus.locked}
379
384
  <Tabs.Trigger value="add" data-label={t__('fields.blocks')}>
380
385
  {t__('fields.blocks')}
@@ -386,15 +391,13 @@
386
391
  <Layers {form} heading={false} />
387
392
  </div>
388
393
  </Tabs.Content>
389
- {#if inspectable}
390
- <Tabs.Content value="inspector" class="rz-blocks-focus__panel-content">
391
- {#if focus.current}
392
- <Stage {form} onRemove={requestRemove} />
393
- {:else}
394
- <p class="rz-blocks-focus__panel-hint">{t__('fields.pick_a_block')}</p>
395
- {/if}
396
- </Tabs.Content>
397
- {/if}
394
+ <Tabs.Content value="inspector" class="rz-blocks-focus__panel-content">
395
+ {#if focus.current}
396
+ <Inspector {form} />
397
+ {:else}
398
+ <p class="rz-blocks-focus__panel-hint">{t__('fields.pick_a_block')}</p>
399
+ {/if}
400
+ </Tabs.Content>
398
401
  {#if !focus.locked}
399
402
  <Tabs.Content value="add" class="rz-blocks-focus__panel-content">
400
403
  <div class="rz-blocks-focus__panel-pad"><Palette {form} heading={false} /></div>
@@ -404,19 +407,18 @@
404
407
  {/snippet}
405
408
 
406
409
  <div class="rz-blocks-focus__body">
407
- {#if focus.hasRenders}
408
- <!-- A click beside the blocks selects the root; the blocks stop their own clicks. -->
409
- <section class="rz-blocks-focus__renders" role="presentation" onclick={focus.selectRoot}>
410
- <Renders {form} list={focus.path ?? ''} onRemove={requestRemove} />
411
- {#if count && !focus.locked}
412
- <StagePlaceholder />
413
- {/if}
414
- </section>
415
- {:else}
416
- <section class="rz-blocks-focus__stage">
417
- <Stage {form} onRemove={requestRemove} />
418
- </section>
419
- {/if}
410
+ <!--
411
+ The stage: the open list, or the narrowed block alone with what it holds. A click beside the
412
+ blocks selects the root; the blocks stop their own clicks.
413
+ -->
414
+ <section class="rz-blocks-focus__renders" role="presentation" onclick={focus.selectRoot}>
415
+ {#key focus.path}
416
+ <Renders {form} list={stageList} only={focus.narrowedRow?.index} onRemove={requestRemove} />
417
+ {/key}
418
+ {#if count && !focus.locked}
419
+ <StagePlaceholder />
420
+ {/if}
421
+ </section>
420
422
 
421
423
  {#if narrow}
422
424
  <Sheet.Root bind:open={panelOpen}>
@@ -462,7 +464,7 @@
462
464
  </Dialog.Root>
463
465
  </div>
464
466
 
465
- <style>/* A level: its fill, a hairline, its shadow. raised, float. */
467
+ <style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
466
468
 
467
469
  /* A well: an input, a track, a dropzone. Its edge shows on hover. */
468
470
 
@@ -562,12 +564,11 @@
562
564
  * The stage, a canvas with the blocks centred on it as wide as the document's column at most,
563
565
  * and the panel on the right.
564
566
  *
565
- * --rz-focus-side: the panel, growing with the room; wider beside renders, where it holds a
566
- * block's fields
567
+ * --rz-focus-side: the panel, growing with the room, where a block's fields want some
567
568
  * --rz-document-width: the blocks' column, 60rem
568
569
  */
569
570
  .rz-blocks-focus__body {
570
- --rz-focus-side: clamp(20rem, 22cqi, 26rem);
571
+ --rz-focus-side: clamp(26rem, 32cqi, 40rem);
571
572
  position: relative;
572
573
  display: grid;
573
574
  grid-template-columns: minmax(0, 1fr) var(--rz-focus-side);
@@ -575,8 +576,7 @@
575
576
  }
576
577
 
577
578
  .rz-blocks-focus__renders > :global(.rz-renders),
578
- .rz-blocks-focus__renders > :global(.rz-stage-placeholder),
579
- .rz-blocks-focus__stage > :global(.rz-stage) {
579
+ .rz-blocks-focus__renders > :global(.rz-stage-placeholder) {
580
580
  max-width: var(--rz-document-width, 60rem);
581
581
  margin-inline: auto;
582
582
  }
@@ -587,13 +587,7 @@
587
587
  margin-top: var(--rz-size-3);
588
588
  }
589
589
 
590
- /* With renders the panel holds a block's fields, which want room. */
591
- .rz-blocks-focus[data-layout='renders'] .rz-blocks-focus__body {
592
- --rz-focus-side: clamp(24rem, 30cqi, 36rem);
593
- }
594
-
595
590
  .rz-blocks-focus__panel,
596
- .rz-blocks-focus__stage,
597
591
  .rz-blocks-focus__renders {
598
592
  min-width: 0;
599
593
  min-height: 0;
@@ -605,7 +599,6 @@
605
599
  border-left: 1px solid var(--rz-border);
606
600
  }
607
601
 
608
- .rz-blocks-focus__stage,
609
602
  .rz-blocks-focus__renders {
610
603
  background-color: var(--rz-bg-well);
611
604
  }
@@ -618,10 +611,6 @@
618
611
  padding: var(--rz-size-14) var(--rz-size-8) var(--rz-size-32);
619
612
  }
620
613
 
621
- .rz-blocks-focus__stage {
622
- padding-bottom: var(--rz-size-16);
623
- }
624
-
625
614
  /* The tabs on the panel's top edge, the content scrolling under them; in a column or a sheet. */
626
615
  /* In a column or in a sheet, which sits outside the overlay: the padding its fields read. */
627
616
  :global(.rz-blocks-focus__panel-tabs.rz-tabs[data-tabs-root]) {
@@ -672,8 +661,7 @@
672
661
 
673
662
  /* Narrow: the stage alone, the panel in a sheet from the right, behind the header's button. */
674
663
  @container rz-focus (max-width: 52rem) {
675
- .rz-blocks-focus__body,
676
- .rz-blocks-focus[data-layout='renders'] .rz-blocks-focus__body {
664
+ .rz-blocks-focus__body {
677
665
  grid-template-columns: minmax(0, 1fr);
678
666
  }
679
667
  }
@@ -0,0 +1,108 @@
1
+ <script lang="ts">
2
+ import { t__ } from '../../../../core/i18n/index.js';
3
+ import { capitalize } from '../../../../util/string.js';
4
+ import { ToyBrick } from '@lucide/svelte';
5
+ import type { Snippet } from 'svelte';
6
+ import type { LayerRow } from './focus.svelte.js';
7
+
8
+ type Props = { row: LayerRow; error?: unknown; children?: Snippet<[name?: string]> };
9
+ const { row, error, children }: Props = $props();
10
+
11
+ const Icon = $derived(row.config?.icon ?? ToyBrick);
12
+ const label = $derived(row.config?.label || capitalize(row.block.type));
13
+
14
+ $effect(() => {
15
+ if (error) console.error(`Render of block ${row.path} failed`, error);
16
+ });
17
+ </script>
18
+
19
+ <!--
20
+ A block without a render, or one whose render threw: a row with its icon, its title and its
21
+ type, then its lists of blocks under it. Its fields are in the inspector.
22
+ -->
23
+ <div class="rz-default-render" data-error={error ? '' : undefined}>
24
+ <p class="rz-default-render__row">
25
+ <span class="rz-default-render__icon"><Icon size={14} /></span>
26
+ <span class="rz-default-render__title">{row.title}</span>
27
+ {#if row.title !== label}
28
+ <span class="rz-default-render__type">{label}</span>
29
+ {/if}
30
+ {#if error}
31
+ <span class="rz-default-render__error">{t__('fields.render_failed')}</span>
32
+ {/if}
33
+ </p>
34
+ {#if row.children.length}
35
+ <div class="rz-default-render__children">{@render children?.()}</div>
36
+ {/if}
37
+ </div>
38
+
39
+ <style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
40
+
41
+ /* A well: an input, a track, a dropzone. Its edge shows on hover. */
42
+
43
+ /* The hover tint, laid over the element's own fill. */
44
+
45
+ /* The picked item of a segmented control. */
46
+
47
+ /* The primary button's face: black on light, white on dark. */
48
+
49
+ /* Keyboard focus on a button, a tab, a link. */
50
+
51
+ /* A focused input: an accent edge and a soft halo. */
52
+
53
+ /* An input with an error. */
54
+ .rz-default-render {
55
+ background-color: var(--rz-bg-raised);
56
+ box-shadow:
57
+ 0 0 0 1px var(--rz-border),
58
+ var(--rz-shadow-raised, 0 0 transparent);
59
+ border-radius: var(--rz-radius-md);
60
+ }
61
+
62
+ .rz-default-render__row {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: var(--rz-size-2);
66
+ min-width: 0;
67
+ height: calc(11 * var(--rz-unit));
68
+ padding-inline: var(--rz-size-3);
69
+ font-size: var(--rz-text-sm);
70
+ }
71
+
72
+ .rz-default-render__icon {
73
+ display: grid;
74
+ place-items: center;
75
+ width: var(--rz-size-6);
76
+ height: var(--rz-size-6);
77
+ flex-shrink: 0;
78
+ border-radius: var(--rz-radius-sm);
79
+ background-color: var(--rz-bg-well);
80
+ color: var(--rz-fg-muted);
81
+ }
82
+
83
+ .rz-default-render__title {
84
+ font-variation-settings: 'wght' 500;
85
+ font-weight: 500;
86
+ min-width: 0;
87
+ overflow: hidden;
88
+ text-overflow: ellipsis;
89
+ white-space: nowrap;
90
+ }
91
+
92
+ .rz-default-render__type {
93
+ flex-shrink: 0;
94
+ font-size: var(--rz-text-xs);
95
+ color: var(--rz-fg-subtle);
96
+ }
97
+
98
+ .rz-default-render__error {
99
+ color: var(--rz-danger);
100
+ }
101
+
102
+ /* The block's lists, indented under its row. */
103
+ .rz-default-render__children {
104
+ display: grid;
105
+ gap: var(--rz-size-3);
106
+ padding: 0 var(--rz-size-3) var(--rz-size-3) var(--rz-size-10);
107
+ }
108
+ </style>
@@ -5,6 +5,6 @@ type Props = {
5
5
  error?: unknown;
6
6
  children?: Snippet<[name?: string]>;
7
7
  };
8
- declare const RenderPlaceholder: import("svelte").Component<Props, {}, "">;
9
- type RenderPlaceholder = ReturnType<typeof RenderPlaceholder>;
10
- export default RenderPlaceholder;
8
+ declare const DefaultRender: import("svelte").Component<Props, {}, "">;
9
+ type DefaultRender = ReturnType<typeof DefaultRender>;
10
+ export default DefaultRender;
@@ -0,0 +1,160 @@
1
+ <script lang="ts">
2
+ import { getFieldListAtPath } from '../../../../core/fields/util.js';
3
+ import { t__ } from '../../../../core/i18n/index.js';
4
+ import RenderFields from '../../../../panel/components/fields/RenderFields.svelte';
5
+ import { Button } from '../../../../panel/components/ui/button/index.js';
6
+ import { withBlockTypes } from '../../../../panel/context/blocks-ops.js';
7
+ import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
8
+ import { Focus, ToyBrick } from '@lucide/svelte';
9
+ import { getBlocksFocusContext } from './focus.svelte.js';
10
+
11
+ type Props = { form: DocumentFormContext };
12
+ const { form }: Props = $props();
13
+
14
+ const focus = getBlocksFocusContext()!;
15
+ const row = $derived(focus.currentRow);
16
+
17
+ /** The selected block's fields, but its lists of blocks: those are on the stage already. */
18
+ const rendered = $derived.by(() => {
19
+ if (!row) return null;
20
+ const { fields, path } = getFieldListAtPath(
21
+ withBlockTypes(row.path, form.values),
22
+ form.config.fields
23
+ );
24
+ return { fields: fields.filter((field) => field.type !== 'blocks'), path };
25
+ });
26
+
27
+ const countOf = (list: string) => {
28
+ const count = form.blocks.list(list).length;
29
+ return count === 1
30
+ ? t__('fields.blocks_count', '1')
31
+ : t__('fields.blocks_count|m|p', String(count));
32
+ };
33
+ </script>
34
+
35
+ {#if row && rendered}
36
+ {@const Icon = row.config?.icon ?? ToyBrick}
37
+ <!-- The selected block: its head, its fields, then how many blocks each of its lists holds. -->
38
+ <article class="rz-inspector" data-block-path={row.path}>
39
+ <header class="rz-inspector__header">
40
+ <span class="rz-inspector__icon"><Icon size={14} /></span>
41
+ <h3>{row.title}</h3>
42
+ <span class="rz-inspector__path">{row.path}</span>
43
+ {#if row.children.length && !focus.isNarrowedBlock(row.path)}
44
+ <Button
45
+ class="rz-inspector__focus"
46
+ variant="ghost"
47
+ size="sm"
48
+ icon={Focus}
49
+ title={t__('fields.focus_block')}
50
+ aria-label={t__('fields.focus_block')}
51
+ onclick={() => focus.open(row.path)}
52
+ >
53
+ {t__('fields.focus')}
54
+ </Button>
55
+ {/if}
56
+ </header>
57
+ <div class="rz-inspector__fields">
58
+ <RenderFields fields={rendered.fields} path={rendered.path} {form} />
59
+ </div>
60
+ {#if row.children.length}
61
+ <ul class="rz-inspector__lists">
62
+ {#each row.children as child (child.list)}
63
+ <li class="rz-inspector__list">
64
+ <span>{child.label}</span>
65
+ <span class="rz-inspector__count">{countOf(child.list)}</span>
66
+ </li>
67
+ {/each}
68
+ </ul>
69
+ {/if}
70
+ </article>
71
+ {/if}
72
+
73
+ <style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
74
+
75
+ /* A well: an input, a track, a dropzone. Its edge shows on hover. */
76
+
77
+ /* The hover tint, laid over the element's own fill. */
78
+
79
+ /* The picked item of a segmented control. */
80
+
81
+ /* The primary button's face: black on light, white on dark. */
82
+
83
+ /* Keyboard focus on a button, a tab, a link. */
84
+
85
+ /* A focused input: an accent edge and a soft halo. */
86
+
87
+ /* An input with an error. */
88
+ /* The head stays on top of the fields, on the page's own fill. */
89
+ .rz-inspector__header {
90
+ position: sticky;
91
+ top: 0;
92
+ z-index: 1;
93
+ display: flex;
94
+ align-items: center;
95
+ gap: var(--rz-size-2);
96
+ height: calc(11.5 * var(--rz-unit));
97
+ padding-inline: var(--rz-size-3);
98
+ border-bottom: 1px solid var(--rz-border);
99
+ background-color: var(--rz-bg-page);
100
+
101
+ h3 {
102
+ font-variation-settings: 'wght' 500;
103
+ font-weight: 500;
104
+ font-size: var(--rz-text-md);
105
+ white-space: nowrap;
106
+ }
107
+ }
108
+
109
+ .rz-inspector__icon {
110
+ display: grid;
111
+ place-items: center;
112
+ width: var(--rz-size-6);
113
+ height: var(--rz-size-6);
114
+ flex-shrink: 0;
115
+ border-radius: var(--rz-radius-sm);
116
+ background-color: var(--rz-bg-well);
117
+ color: var(--rz-fg-muted);
118
+ }
119
+
120
+ .rz-inspector__path {
121
+ min-width: 0;
122
+ font-family: var(--rz-font-mono);
123
+ font-size: var(--rz-text-xs);
124
+ color: var(--rz-fg-subtle);
125
+ overflow: hidden;
126
+ text-overflow: ellipsis;
127
+ white-space: nowrap;
128
+ }
129
+
130
+ /* On the right end of the head. */
131
+ .rz-inspector__header :global(.rz-inspector__focus) {
132
+ flex-shrink: 0;
133
+ margin-left: auto;
134
+ }
135
+
136
+ .rz-inspector__fields {
137
+ padding-block: var(--rz-size-6);
138
+ }
139
+
140
+ /* Under the fields, past a hairline: each list and its count, in quiet text. */
141
+ .rz-inspector__lists {
142
+ display: grid;
143
+ gap: var(--rz-size-1-5);
144
+ margin: 0 var(--rz-fields-padding) var(--rz-size-16);
145
+ padding-top: var(--rz-size-4);
146
+ border-top: 1px solid var(--rz-border);
147
+ font-size: var(--rz-text-sm);
148
+ color: var(--rz-fg-muted);
149
+ }
150
+
151
+ .rz-inspector__list {
152
+ display: flex;
153
+ justify-content: space-between;
154
+ gap: var(--rz-size-2);
155
+ }
156
+
157
+ .rz-inspector__count {
158
+ color: var(--rz-fg-subtle);
159
+ }
160
+ </style>
@@ -0,0 +1,7 @@
1
+ import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
2
+ type Props = {
3
+ form: DocumentFormContext;
4
+ };
5
+ declare const Inspector: import("svelte").Component<Props, {}, "">;
6
+ type Inspector = ReturnType<typeof Inspector>;
7
+ export default Inspector;
@@ -33,7 +33,7 @@
33
33
  </header>
34
34
  {/if}
35
35
  {#if focus.path}
36
- <!-- The root node: the list itself. Selected, the stage shows every block of it. -->
36
+ <!-- The root node: the open list, or the narrowed block. Selected, nothing is. -->
37
37
  <button
38
38
  type="button"
39
39
  class="rz-layers__root"
@@ -43,11 +43,24 @@
43
43
  <span class="rz-layers__root-icon"><LayoutList size={13} /></span>
44
44
  <span class="rz-layers__root-title">{focus.rootLabel()}</span>
45
45
  </button>
46
- <LayersList {form} list={focus.path} depth={1} />
46
+ {#if focus.narrowedRow}
47
+ <!-- Narrowed to a block: the lists it holds, each under its name when there are several. -->
48
+ {@const lists = focus.narrowedRow.children}
49
+ {#each lists as child (child.list)}
50
+ <LayersList
51
+ {form}
52
+ list={child.list}
53
+ depth={1}
54
+ label={lists.length > 1 ? child.label : undefined}
55
+ />
56
+ {/each}
57
+ {:else}
58
+ <LayersList {form} list={focus.path} depth={1} />
59
+ {/if}
47
60
  {/if}
48
61
  </div>
49
62
 
50
- <style>/* A level: its fill, a hairline, its shadow. raised, float. */
63
+ <style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
51
64
 
52
65
  /* A well: an input, a track, a dropzone. Its edge shows on hover. */
53
66