@atom-forge/brickee 0.0.1 → 0.0.2

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 (49) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README-AI.md +24 -21
  3. package/dist/Editor.svelte +52 -64
  4. package/dist/Editor.svelte.d.ts +0 -3
  5. package/dist/LinkPrompt.svelte +3 -3
  6. package/dist/Preview.svelte +1 -5
  7. package/dist/Preview.svelte.d.ts +0 -3
  8. package/dist/PropsBar.svelte +120 -110
  9. package/dist/PropsBar.svelte.d.ts +0 -3
  10. package/dist/code.d.ts +12 -0
  11. package/dist/code.js +15 -0
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/kit/Empty.svelte +2 -2
  15. package/dist/kit/Frame.svelte +3 -3
  16. package/dist/locales/hu.js +2 -7
  17. package/dist/markdown.d.ts +0 -2
  18. package/dist/markdown.js +1 -1
  19. package/dist/plugins/Gap.svelte +1 -1
  20. package/dist/plugins/Map.svelte +1 -1
  21. package/dist/plugins/Table.svelte +36 -62
  22. package/dist/plugins/TablePreview.svelte +2 -2
  23. package/dist/plugins/YouTubePreview.svelte +1 -1
  24. package/dist/plugins/index.js +12 -1
  25. package/dist/schema.js +1 -1
  26. package/dist/types.d.ts +6 -7
  27. package/docs/en/bundled-plugins.md +1 -1
  28. package/docs/en/documents-and-markdown.md +4 -5
  29. package/docs/en/editor-and-preview.md +1 -3
  30. package/docs/en/getting-started.md +6 -2
  31. package/docs/en/host-contexts.md +26 -132
  32. package/docs/en/index.md +4 -4
  33. package/docs/en/recipes-and-pitfalls.md +10 -9
  34. package/docs/en/upgrading.md +20 -4
  35. package/docs/en/writing-plugins.md +111 -11
  36. package/docs/hu/bundled-plugins.md +1 -1
  37. package/docs/hu/documents-and-markdown.md +4 -5
  38. package/docs/hu/editor-and-preview.md +1 -3
  39. package/docs/hu/getting-started.md +6 -2
  40. package/docs/hu/host-contexts.md +26 -132
  41. package/docs/hu/index.md +4 -4
  42. package/docs/hu/recipes-and-pitfalls.md +10 -9
  43. package/docs/hu/upgrading.md +20 -4
  44. package/docs/hu/writing-plugins.md +111 -11
  45. package/package.json +6 -2
  46. package/dist/ImagePicker.svelte +0 -131
  47. package/dist/ImagePicker.svelte.d.ts +0 -13
  48. package/dist/media.d.ts +0 -17
  49. package/dist/media.js +0 -12
@@ -1,31 +1,27 @@
1
- <!-- The fields of a plugin block, on the top of its box. Closed: only a small header (the block's tag); a click on it
2
- opens the fields in place: a wrapping row (label and control side by side), text areas on their own full-width rows. An image field shows the picked image(s); a click
3
- opens the picker (ImagePicker) with all the document's images. -->
1
+ <!-- The fields of a plugin block (or a code block), on the top of its box. Closed: only a small header (the block's
2
+ tag); a click on it opens the fields in place: a wrapping row (label and control side by side), text areas on their
3
+ own full-width rows. -->
4
4
  <script lang="ts">
5
- import { ColorPicker, Input, NativeSelect, Slider, Textarea, getPopupManager } from '@atom-forge/ui';
5
+ import { ColorPicker, Input, NativeSelect, Slider, Textarea } from '@atom-forge/ui';
6
6
  import ChevronDown from '@lucide/svelte/icons/chevron-down';
7
7
  import { slide } from 'svelte/transition';
8
- import ImagePicker from './ImagePicker.svelte';
9
8
  import { useView } from './view';
10
9
  import type { Translate } from './i18n';
11
- import type { MediaItem } from './media';
12
10
  import type { Block, PropField } from './types';
13
11
 
14
12
  interface Props {
15
13
  block: Block;
16
14
  tag: string;
17
15
  fields: PropField[];
18
- media: MediaItem[];
19
16
  tr: Translate;
20
17
  /** Sets one property from its field's text and returns the text as it is now kept. */
21
18
  setProp: (b: Block, f: PropField, raw: string) => string;
22
19
  /** Sets one property to a value as it is ('' or undefined removes it). */
23
20
  setValue: (b: Block, key: string, v: unknown) => void;
24
- pickMedia: (b: Block, f: PropField, id: string) => void;
25
21
  /** Start with the fields open (a block just made). */
26
22
  open?: boolean;
27
23
  }
28
- let { block, tag, fields, media, tr, setProp, setValue, pickMedia, open: startOpen = false }: Props = $props();
24
+ let { block, tag, fields, tr, setProp, setValue, open: startOpen = false }: Props = $props();
29
25
  // svelte-ignore state_referenced_locally
30
26
  let open = $state(startOpen);
31
27
 
@@ -33,10 +29,18 @@
33
29
  const v = block.props?.[f.key];
34
30
  return f.format ? f.format(v) : v == null ? '' : String(v);
35
31
  };
36
- const picked = (f: PropField): string[] => {
32
+ /** A text field's placeholder: its label, and its own placeholder (an example) after it. */
33
+ const hint = (f: PropField) => [tr(f.label), f.placeholder && tr(f.placeholder)].filter(Boolean).join(' · ');
34
+ /** Toggles: the values switched on, kept in the order of the options. */
35
+ const toggled = (f: PropField): string[] => {
37
36
  const v = block.props?.[f.key];
38
- return Array.isArray(v) ? v : v ? [String(v)] : [];
37
+ return Array.isArray(v) ? v.map(String) : [];
39
38
  };
39
+ function toggle(f: PropField, value: string) {
40
+ const on = new Set(toggled(f));
41
+ if (!on.delete(value)) on.add(value);
42
+ setValue(block, f.key, (f.options ?? []).map((o) => o.value).filter((x) => on.has(x)));
43
+ }
40
44
  const optionLabel = (f: PropField, i: number) => {
41
45
  const opt = f.options?.[i];
42
46
  return opt ? tr(opt.label, { n: opt.value }) : '';
@@ -107,19 +111,9 @@
107
111
 
108
112
  const short = $derived(fields.filter((f) => f.kind !== 'textarea'));
109
113
  const long = $derived(fields.filter((f) => f.kind === 'textarea'));
110
-
111
- const popups = getPopupManager();
112
- const urlOf = (id: string) => media.find((m) => m.id === id);
113
- function openPicker(e: MouseEvent, f: PropField) {
114
- popups.open.component(
115
- ImagePicker,
116
- { media, multiple: f.kind === 'images', getPicked: () => picked(f), pick: (id: string) => pickMedia(block, f, id), tr },
117
- { anchor: e, align: 'left' }
118
- );
119
- }
120
114
  </script>
121
115
 
122
- <div class="light bar" class:open>
116
+ <div class="bar" class:open>
123
117
  <button type="button" class="head" aria-expanded={open} title={tr(open ? 'Hide settings' : 'Settings')} onmousedown={(e) => e.preventDefault()} onclick={() => (open = !open)}>
124
118
  <span class="tag">{tag}</span>
125
119
  <ChevronDown size={13} class="chev" />
@@ -128,36 +122,46 @@
128
122
  <div class="body" transition:slide={{ duration: 180 }}>
129
123
  <div class="grid">
130
124
  {#each short as f (f.key)}
131
- {#if f.kind === 'image' || f.kind === 'images'}
132
- {@const ids = picked(f)}
133
- <div class="field">
134
- <span class="name">{tr(f.label)}</span>
135
- <button type="button" class="chosen" title={tr('Choose')} onclick={(e) => openPicker(e, f)}>
136
- {#each ids as id, n (id)}
137
- {@const m = urlOf(id)}
138
- {#if m}<img src={m.url} alt={m.name} />{:else}<span class="missing" title={id}>?</span>{/if}
139
- {#if f.kind === 'images' && n === 5 && ids.length > 6}<span class="more">+{ids.length - 6}</span>{/if}
140
- {:else}
141
- <span class="empty">{tr('Choose…')}</span>
142
- {/each}
143
- </button>
144
- </div>
125
+ {#if f.kind === 'text'}
126
+ <!-- the field shows the value as kept (a YouTube link becomes its id); its label is the placeholder -->
127
+ <label class="field" title={tr(f.label)}>
128
+ <span class="sr">{tr(f.label)}</span>
129
+ <Input small monospace placeholder={hint(f)} bind:value={() => text(f), (v: string) => setProp(block, f, v)} />
130
+ </label>
145
131
  {:else}
146
- <!-- not a label around buttons (a slider's view buttons, a colour's clear): a click on a label goes to its first button -->
147
- <svelte:element this={f.kind === 'slider' || f.kind === 'color' ? 'div' : 'label'} class="field">
132
+ <!-- not a label around buttons (a slider's view buttons, a colour's clear, toggles): a click on a label goes to its first button -->
133
+ <svelte:element this={f.kind === 'select' ? 'label' : 'div'} class="field inline" role={f.kind === 'toggles' ? 'group' : undefined} aria-label={f.kind === 'toggles' ? tr(f.label) : undefined}>
148
134
  <span class="name"
149
135
  >{tr(f.label)}{#if viewLabel(f)}<span class="view" class:own={current(f).mine}>{viewLabel(f)}</span>{/if}</span
150
136
  >
151
137
  {#if f.kind === 'select'}
152
138
  <NativeSelect
139
+ small
153
140
  options={(f.options ?? []).map((opt) => ({ value: opt.value, label: tr(opt.label, { n: opt.value }) }))}
154
141
  bind:value={() => text(f), (v: string) => setProp(block, f, v)}
155
142
  />
143
+ {:else if f.kind === 'toggles'}
144
+ {@const on = toggled(f)}
145
+ <span class="toggles">
146
+ {#each f.options ?? [] as opt (opt.value)}
147
+ <button
148
+ type="button"
149
+ class="toggle"
150
+ class:on={on.includes(opt.value)}
151
+ aria-pressed={on.includes(opt.value)}
152
+ title={tr(opt.label)}
153
+ aria-label={tr(opt.label)}
154
+ onmousedown={(e) => e.preventDefault()}
155
+ onclick={() => toggle(f, opt.value)}
156
+ >{#if opt.icon}<opt.icon size={15} />{:else}{tr(opt.label)}{/if}</button
157
+ >
158
+ {/each}
159
+ </span>
156
160
  {:else if f.kind === 'slider'}
157
161
  <span class="line">
158
162
  <span class="slider">
159
163
  <Slider
160
- compact
164
+ small
161
165
  drawStops={!free(f) && (f.options?.length ?? 0) <= 10}
162
166
  min={free(f) ? low(f) : 0}
163
167
  max={free(f) ? f.max : (f.options?.length ?? 1) - 1}
@@ -175,25 +179,23 @@
175
179
  <span class="swatch" aria-hidden="true"></span>{tr(f.none)}
176
180
  </button>
177
181
  {:else}
178
- <ColorPicker bind:value={() => text(f) || '#000000', (v: string) => setProp(block, f, v)} />
182
+ <ColorPicker small bind:value={() => text(f) || '#000000', (v: string) => setProp(block, f, v)} />
179
183
  {#if f.none}
180
184
  <button type="button" class="clear" title={tr(f.none)} aria-label={tr(f.none)} onclick={() => setProp(block, f, '')}>×</button>
181
185
  {/if}
182
186
  {/if}
183
187
  </span>
184
- {:else}
185
- <!-- the field shows the value as kept (a YouTube link becomes its id) -->
186
- <Input monospace placeholder={f.placeholder && tr(f.placeholder)} bind:value={() => text(f), (v: string) => setProp(block, f, v)} />
187
188
  {/if}
188
189
  </svelte:element>
189
190
  {/if}
190
191
  {/each}
191
192
  {#each long as f (f.key)}
192
- <label class="field long" onfocusin={() => (editing = { key: f.key, text: text(f) })} onfocusout={() => (editing = null)}>
193
- <span class="name">{tr(f.label)}</span>
193
+ <label class="field long" title={tr(f.label)} onfocusin={() => (editing = { key: f.key, text: text(f) })} onfocusout={() => (editing = null)}>
194
+ <span class="sr">{tr(f.label)}</span>
194
195
  <Textarea
195
- rows={3}
196
- placeholder={f.placeholder && tr(f.placeholder)}
196
+ small
197
+ rows={2}
198
+ placeholder={hint(f)}
197
199
  bind:value={() => (editing?.key === f.key ? editing.text : text(f)), (v: string) => {
198
200
  if (editing?.key === f.key) editing.text = v;
199
201
  setProp(block, f, v);
@@ -214,12 +216,12 @@
214
216
  margin-bottom: 4px;
215
217
  border-radius: 8px;
216
218
  font: 12px/1.4 system-ui, sans-serif;
217
- color: #1d1d1f;
219
+ color: var(--color-surface-contrast, #1d1d1f);
218
220
  }
219
221
  .bar.open {
220
222
  justify-items: stretch;
221
223
  margin-bottom: 8px;
222
- padding: 8px 12px 12px;
224
+ padding: 6px 8px 8px;
223
225
  background: rgba(120, 120, 140, 0.07);
224
226
  }
225
227
  .bar {
@@ -227,12 +229,13 @@
227
229
  padding 0.18s,
228
230
  background 0.18s;
229
231
  }
230
- /* the fields in 1–3 columns (as wide as the box allows), each with its label above */
232
+ /* the fields in columns as wide as the box allows; text fields carry their label as placeholder, the others a short
233
+ label beside the control */
231
234
  .grid {
232
235
  display: grid;
233
- grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
234
- gap: 12px 16px;
235
- padding-top: 8px;
236
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
237
+ gap: 6px 10px;
238
+ padding-top: 6px;
236
239
  }
237
240
  .head {
238
241
  display: flex;
@@ -241,13 +244,13 @@
241
244
  padding: 0;
242
245
  border: 0;
243
246
  background: none;
244
- color: #8e8e96;
247
+ color: var(--color-muted-contrast, #8e8e96);
245
248
  cursor: pointer;
246
249
  justify-self: start;
247
250
  }
248
251
  .head:hover .tag {
249
252
  background: rgba(120, 120, 140, 0.2);
250
- color: #1d1d1f;
253
+ color: var(--color-surface-contrast, #1d1d1f);
251
254
  }
252
255
  .head :global(.chev) {
253
256
  transition: rotate 0.15s;
@@ -259,7 +262,7 @@
259
262
  padding: 1px 6px;
260
263
  border-radius: 5px;
261
264
  background: rgba(120, 120, 140, 0.12);
262
- color: #6e6e76;
265
+ color: var(--color-muted-contrast, #6e6e76);
263
266
  font: 500 11px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
264
267
  white-space: nowrap;
265
268
  user-select: none;
@@ -267,9 +270,56 @@
267
270
  .field {
268
271
  display: grid;
269
272
  align-content: start;
270
- gap: 4px;
271
273
  min-width: 0;
272
274
  }
275
+ .field.inline {
276
+ grid-template-columns: auto minmax(0, 1fr);
277
+ align-items: center;
278
+ gap: 8px;
279
+ }
280
+ /* compact controls: the bar's small type in the inputs too */
281
+ .field :global(input:not([type='range'])),
282
+ .field :global(textarea),
283
+ .field :global(select) {
284
+ font-size: 12px;
285
+ }
286
+ /* the label of a field whose placeholder shows it */
287
+ .sr {
288
+ position: absolute;
289
+ width: 1px;
290
+ height: 1px;
291
+ overflow: hidden;
292
+ clip-path: inset(50%);
293
+ white-space: nowrap;
294
+ }
295
+ .toggles {
296
+ display: inline-flex;
297
+ justify-self: start;
298
+ gap: 1px;
299
+ padding: 2px;
300
+ border-radius: 7px;
301
+ background: var(--color-muted, #f4f4f6);
302
+ }
303
+ .toggle {
304
+ display: inline-grid;
305
+ place-items: center;
306
+ min-width: 26px;
307
+ height: 24px;
308
+ padding: 0 4px;
309
+ border: 0;
310
+ border-radius: 5px;
311
+ background: none;
312
+ color: var(--color-muted-contrast, #6e6e76);
313
+ cursor: pointer;
314
+ }
315
+ .toggle:hover {
316
+ color: var(--color-surface-contrast, #1d1d1f);
317
+ }
318
+ .toggle.on {
319
+ background: var(--color-surface, #fff);
320
+ color: #3b82f6;
321
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
322
+ }
273
323
  /* text areas take a whole row */
274
324
  .field.long {
275
325
  grid-column: 1 / -1;
@@ -283,7 +333,7 @@
283
333
  .name {
284
334
  font-size: 11.5px;
285
335
  font-weight: 600;
286
- color: #8e8e96;
336
+ color: var(--color-muted-contrast, #8e8e96);
287
337
  white-space: nowrap;
288
338
  user-select: none;
289
339
  }
@@ -291,15 +341,15 @@
291
341
  .view {
292
342
  margin-left: 6px;
293
343
  padding: 0 5px;
294
- border: 1px dashed #c8c8d0;
344
+ border: 1px dashed var(--color-frame, #c8c8d0);
295
345
  border-radius: 4px;
296
- color: #6e6e76;
346
+ color: var(--color-muted-contrast, #6e6e76);
297
347
  font-weight: 500;
298
348
  }
299
349
  .view.own {
300
350
  border-style: solid;
301
- border-color: #1d1d1f;
302
- color: #1d1d1f;
351
+ border-color: var(--color-surface-contrast, #1d1d1f);
352
+ color: var(--color-surface-contrast, #1d1d1f);
303
353
  }
304
354
  .slider {
305
355
  display: block;
@@ -308,7 +358,7 @@
308
358
  }
309
359
  .value {
310
360
  min-width: 4.5em;
311
- color: #3a3a40;
361
+ color: var(--color-surface-contrast, #3a3a40);
312
362
  font-variant-numeric: tabular-nums;
313
363
  white-space: nowrap;
314
364
  }
@@ -318,21 +368,21 @@
318
368
  gap: 6px;
319
369
  height: 30px;
320
370
  padding: 0 10px 0 6px;
321
- border: 1px dashed #c8c8d0;
371
+ border: 1px dashed var(--color-frame, #c8c8d0);
322
372
  border-radius: 7px;
323
- background: #fff;
324
- color: #8e8e96;
373
+ background: var(--color-surface, #fff);
374
+ color: var(--color-muted-contrast, #8e8e96);
325
375
  cursor: pointer;
326
376
  }
327
377
  .nocolor:hover {
328
378
  border-color: var(--color-accent, #ea580c);
329
- color: #3a3a40;
379
+ color: var(--color-surface-contrast, #3a3a40);
330
380
  }
331
381
  /* an empty swatch, struck through */
332
382
  .swatch {
333
383
  width: 16px;
334
384
  height: 16px;
335
- border: 1px solid #c8c8d0;
385
+ border: 1px solid var(--color-frame, #c8c8d0);
336
386
  border-radius: 4px;
337
387
  background: linear-gradient(to top right, transparent calc(50% - 1px), #e5484d calc(50% - 1px), #e5484d calc(50% + 1px), transparent calc(50% + 1px));
338
388
  }
@@ -343,53 +393,13 @@
343
393
  border: 0;
344
394
  border-radius: 6px;
345
395
  background: none;
346
- color: #8e8e96;
396
+ color: var(--color-muted-contrast, #8e8e96);
347
397
  font-size: 16px;
348
398
  line-height: 1;
349
399
  cursor: pointer;
350
400
  }
351
401
  .clear:hover {
352
402
  background: rgba(120, 120, 140, 0.14);
353
- color: #1d1d1f;
354
- }
355
- .chosen {
356
- display: flex;
357
- align-items: center;
358
- gap: 3px;
359
- min-height: 30px;
360
- padding: 2px;
361
- border: 1px solid #dcdce2;
362
- border-radius: 7px;
363
- background: #fff;
364
- cursor: pointer;
365
- }
366
- .chosen:hover {
367
- border-color: var(--color-accent, #ea580c);
368
- }
369
- /* images after the sixth are a "+n" */
370
- .chosen > img:nth-of-type(n + 7) {
371
- display: none;
372
- }
373
- .chosen img,
374
- .chosen .missing {
375
- width: 40px;
376
- height: 24px;
377
- object-fit: cover;
378
- border-radius: 4px;
379
- }
380
- .chosen .missing {
381
- display: grid;
382
- place-items: center;
383
- background: #eee;
384
- color: #8e8e96;
385
- }
386
- .chosen .more {
387
- padding: 0 4px;
388
- color: #6e6e76;
389
- font-size: 11px;
390
- }
391
- .chosen .empty {
392
- padding: 0 8px;
393
- color: #8e8e96;
403
+ color: var(--color-surface-contrast, #1d1d1f);
394
404
  }
395
405
  </style>
@@ -1,17 +1,14 @@
1
1
  import type { Translate } from './i18n';
2
- import type { MediaItem } from './media';
3
2
  import type { Block, PropField } from './types';
4
3
  interface Props {
5
4
  block: Block;
6
5
  tag: string;
7
6
  fields: PropField[];
8
- media: MediaItem[];
9
7
  tr: Translate;
10
8
  /** Sets one property from its field's text and returns the text as it is now kept. */
11
9
  setProp: (b: Block, f: PropField, raw: string) => string;
12
10
  /** Sets one property to a value as it is ('' or undefined removes it). */
13
11
  setValue: (b: Block, key: string, v: unknown) => void;
14
- pickMedia: (b: Block, f: PropField, id: string) => void;
15
12
  /** Start with the fields open (a block just made). */
16
13
  open?: boolean;
17
14
  }
package/dist/code.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /** A language: its value is stored in the block (`props.lang`, the opening fence's info string). */
2
+ export interface CodeLanguage {
3
+ value: string;
4
+ /** Shown in the dropdown; defaults to the value. */
5
+ label?: string;
6
+ }
7
+ type Get = () => CodeLanguage[];
8
+ /** Call in a component's init (around the editor). Without its own list, a nested editor keeps its parent's. */
9
+ export declare function provideCodeLanguages(own: () => (string | CodeLanguage)[] | undefined): void;
10
+ /** Call in a component's init; the returned function reads the current list (empty: free text). */
11
+ export declare const useCodeLanguages: () => Get;
12
+ export {};
package/dist/code.js ADDED
@@ -0,0 +1,15 @@
1
+ // The languages a code block offers. Without a list (the default) its language is free text; with one, the field is a
2
+ // dropdown of these. Which languages make sense is the host's business (what its site can highlight).
3
+ import { getContext, setContext } from 'svelte';
4
+ const KEY = 'block-editor:code-languages';
5
+ const normalize = (list) => list.map((l) => (typeof l === 'string' ? { value: l } : l));
6
+ /** Call in a component's init (around the editor). Without its own list, a nested editor keeps its parent's. */
7
+ export function provideCodeLanguages(own) {
8
+ const parent = getContext(KEY);
9
+ setContext(KEY, () => {
10
+ const list = own();
11
+ return list ? normalize(list) : (parent?.() ?? []);
12
+ });
13
+ }
14
+ /** Call in a component's init; the returned function reads the current list (empty: free text). */
15
+ export const useCodeLanguages = () => getContext(KEY) ?? (() => []);
package/dist/index.d.ts CHANGED
@@ -5,8 +5,8 @@ export { default as Empty } from './kit/Empty.svelte';
5
5
  export * from './kit/util';
6
6
  export * from './model';
7
7
  export { inline, fromStored, toStored, fromMarkdown, toMarkdown } from './markdown';
8
- export { provideMedia, useMedia, findMedia, type MediaItem } from './media';
9
8
  export { provideView, useView } from './view';
9
+ export { provideCodeLanguages, useCodeLanguages, type CodeLanguage } from './code';
10
10
  export { scrollSync, scrollFraction, setScrollFraction, type ScrollSync } from './scroll';
11
11
  export { provideText, useText, translator, type Messages, type Translate } from './i18n';
12
12
  export { PALETTE_ITEMS, BUILT_IN_IDS, narrowPalette, type Icon, type PaletteItem } from './palette';
package/dist/index.js CHANGED
@@ -9,8 +9,8 @@ export { default as Empty } from './kit/Empty.svelte';
9
9
  export * from './kit/util';
10
10
  export * from './model';
11
11
  export { inline, fromStored, toStored, fromMarkdown, toMarkdown } from './markdown';
12
- export { provideMedia, useMedia, findMedia } from './media';
13
12
  export { provideView, useView } from './view';
13
+ export { provideCodeLanguages, useCodeLanguages } from './code';
14
14
  export { scrollSync, scrollFraction, setScrollFraction } from './scroll';
15
15
  export { provideText, useText, translator } from './i18n';
16
16
  export { PALETTE_ITEMS, BUILT_IN_IDS, narrowPalette } from './palette';
@@ -16,9 +16,9 @@
16
16
  justify-content: center;
17
17
  gap: 8px;
18
18
  min-height: 96px;
19
- border: 1px dashed #d4d4da;
19
+ border: 1px dashed var(--color-frame, #d4d4da);
20
20
  border-radius: 10px;
21
- color: #a0a0a8;
21
+ color: var(--color-muted-contrast, #a0a0a8);
22
22
  font: 14px system-ui, sans-serif;
23
23
  }
24
24
  </style>
@@ -46,7 +46,7 @@
46
46
  <style>
47
47
  .frame {
48
48
  position: relative;
49
- border: 1px solid #e5e5ea;
49
+ border: 1px solid var(--color-frame, #e5e5ea);
50
50
  border-radius: 10px;
51
51
  /* left: room for the inner blocks' handle bar (22px left of the row, which reaches 8px out) */
52
52
  padding: 0.8em 1.1em 0.4em calc(30px + 0.5em);
@@ -61,7 +61,7 @@
61
61
  gap: 8px;
62
62
  margin: 0 9em 0.3em 0;
63
63
  font: 600 13px/1.4 system-ui, sans-serif;
64
- color: #1d1d1f;
64
+ color: var(--color-surface-contrast, #1d1d1f);
65
65
  }
66
66
  .head img {
67
67
  height: 28px;
@@ -71,6 +71,6 @@
71
71
  }
72
72
  .muted {
73
73
  font-weight: 400;
74
- color: #a0a0a8;
74
+ color: var(--color-muted-contrast, #a0a0a8);
75
75
  }
76
76
  </style>
@@ -8,12 +8,6 @@ export const hu = {
8
8
  Settings: 'Beállítások',
9
9
  'Hide settings': 'Beállítások elrejtése',
10
10
  None: 'Nincs',
11
- Images: 'Képek',
12
- Choose: 'Választás',
13
- 'Choose…': 'Válassz…',
14
- '{n} picked': '{n} kiválasztva',
15
- language: 'nyelv',
16
- 'No images attached to this page yet.': 'Még nincs kép csatolva.',
17
11
  'New block at the end': 'Új blokk a végére',
18
12
  Formatting: 'Formázás',
19
13
  'Turn into': 'Átalakítás',
@@ -131,9 +125,10 @@ export const hu = {
131
125
  'Align column right': 'Az oszlop jobbra zárva',
132
126
  'Header row': 'Fejléc (első sor)',
133
127
  'Footer row (e.g. sums)': 'Lábléc (utolsó sor, pl. összesítő)',
128
+ 'Header and footer': 'Fejléc és lábléc',
129
+ 'Click a cell to edit its row and column': 'Kattints egy cellába a sora és oszlopa szerkesztéséhez',
134
130
  'Drag to move the row': 'Húzd a sor áthelyezéséhez',
135
131
  'Drag to move the column': 'Húzd az oszlop áthelyezéséhez',
136
- 'Enter: next row · Shift+Enter: line break · paste from a spreadsheet': 'Enter: következő sor · Shift+Enter: sortörés · táblázatból be is illeszthető',
137
132
  Heading: 'Fejléc',
138
133
  'Row {r}, column {c}': '{r}. sor, {c}. oszlop',
139
134
  'Add a column': 'Új oszlop',
@@ -1,4 +1,3 @@
1
- import type { MediaItem } from './media';
2
1
  import { type Block, type BlockPlugin, type StoredBlock } from './types';
3
2
  /** Inline markdown -> inline html (b, i, u, sub, sup, strike, code, a, br). Backslash escapes are honoured; links are
4
3
  * http(s), mailto, tel or site-relative only. */
@@ -21,5 +20,4 @@ export declare function fromMarkdown(src: string): Block[];
21
20
  * plugin's `markdown`; one without it is left out. */
22
21
  export declare function toMarkdown(blocks: Block[], opts?: {
23
22
  plugins?: BlockPlugin[];
24
- media?: MediaItem[];
25
23
  }): string;
package/dist/markdown.js CHANGED
@@ -202,7 +202,7 @@ export function toMarkdown(blocks, opts = {}) {
202
202
  if (!plugin?.markdown)
203
203
  return '';
204
204
  const inner = b.blocks?.length ? toMarkdown(b.blocks.map(fromStored), opts) : '';
205
- return plugin.markdown(b.props ?? {}, { inner, media: opts.media ?? [] }).trim();
205
+ return plugin.markdown(b.props ?? {}, { inner }).trim();
206
206
  };
207
207
  let out = '';
208
208
  let prev;
@@ -23,6 +23,6 @@
23
23
  <style>
24
24
  .gap {
25
25
  border-radius: 6px;
26
- background: repeating-linear-gradient(-45deg, transparent 0 6px, rgb(0 0 0 / 0.05) 6px 12px);
26
+ background: repeating-linear-gradient(-45deg, transparent 0 6px, color-mix(in srgb, currentColor 7%, transparent) 6px 12px);
27
27
  }
28
28
  </style>
@@ -33,7 +33,7 @@
33
33
 
34
34
  <style>
35
35
  .map {
36
- border: 1px solid #e5e5ea;
36
+ border: 1px solid var(--color-frame, #e5e5ea);
37
37
  border-radius: 10px;
38
38
  overflow: hidden;
39
39
  }