@formicoidea/labre-core 0.39.1 → 0.40.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 (37) hide show
  1. package/dist/_pkgs/affine-block-callout/emoji-margin.js +19 -11
  2. package/dist/_pkgs/affine-block-list/list-block.d.ts +8 -1
  3. package/dist/_pkgs/affine-block-list/list-block.js +27 -17
  4. package/dist/_pkgs/affine-block-note/configs/tooltips.d.ts +16 -0
  5. package/dist/_pkgs/affine-block-note/configs/tooltips.js +99 -66
  6. package/dist/_pkgs/affine-block-paragraph/paragraph-block.d.ts +8 -1
  7. package/dist/_pkgs/affine-block-paragraph/paragraph-block.js +30 -15
  8. package/dist/_pkgs/affine-block-paragraph/styles.js +30 -83
  9. package/dist/_pkgs/affine-block-paragraph/turbo/paragraph-layout-handler.js +1 -0
  10. package/dist/_pkgs/affine-block-paragraph/turbo/paragraph-painter.worker.d.ts +2 -0
  11. package/dist/_pkgs/affine-block-paragraph/turbo/paragraph-painter.worker.js +6 -1
  12. package/dist/_pkgs/affine-block-root/edgeless/clipboard/clipboard.js +3 -3
  13. package/dist/_pkgs/affine-block-root/keyboard/keymap.js +20 -0
  14. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.d.ts +6 -4
  15. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +15 -10
  16. package/dist/_pkgs/affine-block-surface/framework-background/def.d.ts +4 -1
  17. package/dist/_pkgs/affine-block-surface/framework-background/def.js +6 -2
  18. package/dist/_pkgs/affine-block-surface/utils/priority-queue.js +2 -2
  19. package/dist/_pkgs/affine-components/toggle-button/toggle-button.d.ts +5 -0
  20. package/dist/_pkgs/affine-components/toggle-button/toggle-button.js +31 -18
  21. package/dist/_pkgs/affine-gfx-template/builtin/other.js +31 -14
  22. package/dist/_pkgs/affine-inline-preset/markdown.d.ts +3 -0
  23. package/dist/_pkgs/affine-inline-preset/markdown.js +19 -0
  24. package/dist/_pkgs/affine-shared/adapters/middlewares/proxy.d.ts +10 -0
  25. package/dist/_pkgs/affine-shared/adapters/middlewares/proxy.js +19 -12
  26. package/dist/_pkgs/affine-shared/adapters/utils/fetch.js +4 -0
  27. package/dist/_pkgs/affine-shared/consts/heading.d.ts +29 -0
  28. package/dist/_pkgs/affine-shared/consts/heading.js +70 -0
  29. package/dist/_pkgs/affine-shared/consts/index.d.ts +2 -0
  30. package/dist/_pkgs/affine-shared/consts/index.js +2 -0
  31. package/dist/_pkgs/affine-shared/consts/notation.d.ts +67 -0
  32. package/dist/_pkgs/affine-shared/consts/notation.js +65 -0
  33. package/dist/_pkgs/std/gfx/model/surface/element-model.d.ts +2 -2
  34. package/dist/_pkgs/std/gfx/model/surface/element-model.js +2 -2
  35. package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +1 -1
  36. package/dist/_pkgs/std/gfx/model/surface/surface-model.js +1 -1
  37. package/package.json +1 -1
@@ -1,5 +1,32 @@
1
+ import { HEADING_LEVELS, HEADING_SCALE } from '../affine-shared/consts/index.js';
1
2
  import { unsafeCSSVarV2 } from '../affine-shared/theme/index.js';
2
- import { css } from 'lit';
3
+ import { css, unsafeCSS } from 'lit';
4
+ /** Inline code is set this much smaller than the text around it. */
5
+ const INLINE_CODE_SHRINK_PX = 3;
6
+ /**
7
+ * H1…H6, generated from `HEADING_SCALE` so every size, line box and margin has
8
+ * one source. Inline code in a heading stays `INLINE_CODE_SHRINK_PX` below the
9
+ * heading's size; H6, the level closest to body text, keeps the body's code
10
+ * padding (with its 2px bottom).
11
+ */
12
+ const headingStyles = unsafeCSS(HEADING_LEVELS.map(level => {
13
+ const { fontSize, fontWeight, letterSpacing, lineHeightExtra, marginTop } = HEADING_SCALE[level];
14
+ return `
15
+ .${level} {
16
+ font-size: ${fontSize}px;
17
+ font-weight: ${fontWeight};
18
+ letter-spacing: ${letterSpacing}em;
19
+ line-height: calc(1em + ${lineHeightExtra}px);
20
+ margin-top: ${marginTop}px;
21
+ margin-bottom: 10px;
22
+ }
23
+
24
+ .${level} code {
25
+ font-size: ${fontSize - INLINE_CODE_SHRINK_PX}px;
26
+ padding: ${level === 'h6' ? '0px 4px 2px' : '0px 4px'};
27
+ }
28
+ `;
29
+ }).join(''));
3
30
  export const paragraphBlockStyles = css `
4
31
  affine-paragraph {
5
32
  box-sizing: border-box;
@@ -21,91 +48,11 @@ export const paragraphBlockStyles = css `
21
48
  }
22
49
 
23
50
  affine-paragraph code {
24
- font-size: calc(var(--affine-font-base) - 3px);
51
+ font-size: calc(var(--affine-font-base) - ${INLINE_CODE_SHRINK_PX}px);
25
52
  padding: 0px 4px 2px;
26
53
  }
27
54
 
28
- .h1 {
29
- font-size: var(--affine-font-h-1);
30
- font-weight: 700;
31
- letter-spacing: -0.02em;
32
- line-height: calc(1em + 8px);
33
- margin-top: 18px;
34
- margin-bottom: 10px;
35
- }
36
-
37
- .h1 code {
38
- font-size: calc(var(--affine-font-base) + 10px);
39
- padding: 0px 4px;
40
- }
41
-
42
- .h2 {
43
- font-size: var(--affine-font-h-2);
44
- font-weight: 600;
45
- letter-spacing: -0.02em;
46
- line-height: calc(1em + 10px);
47
- margin-top: 14px;
48
- margin-bottom: 10px;
49
- }
50
-
51
- .h2 code {
52
- font-size: calc(var(--affine-font-base) + 8px);
53
- padding: 0px 4px;
54
- }
55
-
56
- .h3 {
57
- font-size: var(--affine-font-h-3);
58
- font-weight: 600;
59
- letter-spacing: -0.02em;
60
- line-height: calc(1em + 8px);
61
- margin-top: 12px;
62
- margin-bottom: 10px;
63
- }
64
-
65
- .h3 code {
66
- font-size: calc(var(--affine-font-base) + 6px);
67
- padding: 0px 4px;
68
- }
69
-
70
- .h4 {
71
- font-size: var(--affine-font-h-4);
72
- font-weight: 600;
73
- letter-spacing: -0.015em;
74
- line-height: calc(1em + 8px);
75
- margin-top: 12px;
76
- margin-bottom: 10px;
77
- }
78
- .h4 code {
79
- font-size: calc(var(--affine-font-base) + 4px);
80
- padding: 0px 4px;
81
- }
82
-
83
- .h5 {
84
- font-size: var(--affine-font-h-5);
85
- font-weight: 600;
86
- letter-spacing: -0.015em;
87
- line-height: calc(1em + 8px);
88
- margin-top: 12px;
89
- margin-bottom: 10px;
90
- }
91
- .h5 code {
92
- font-size: calc(var(--affine-font-base) + 2px);
93
- padding: 0px 4px;
94
- }
95
-
96
- .h6 {
97
- font-size: var(--affine-font-h-6);
98
- font-weight: 600;
99
- letter-spacing: -0.015em;
100
- line-height: calc(1em + 8px);
101
- margin-top: 12px;
102
- margin-bottom: 10px;
103
- }
104
-
105
- .h6 code {
106
- font-size: var(--affine-font-base);
107
- padding: 0px 4px 2px;
108
- }
55
+ ${headingStyles}
109
56
 
110
57
  .quote {
111
58
  line-height: 26px;
@@ -19,6 +19,7 @@ export class ParagraphLayoutHandlerExtension extends BlockLayoutHandlerExtension
19
19
  const { zoom, viewScale } = viewportRecord;
20
20
  const paragraph = {
21
21
  type: 'affine:paragraph',
22
+ paragraphType: model.props.type,
22
23
  sentences: [],
23
24
  blockId: model.id,
24
25
  rect: { x: 0, y: 0, w: 0, h: 0 },
@@ -6,6 +6,8 @@ interface SentenceLayout {
6
6
  }
7
7
  export interface ParagraphLayout extends BlockLayout {
8
8
  type: 'affine:paragraph';
9
+ /** The paragraph block's own `props.type`: `text`, `quote`, `h1`…`h6`. */
10
+ paragraphType: string;
9
11
  sentences: SentenceLayout[];
10
12
  }
11
13
  export declare const ParagraphLayoutPainterExtension: import("../../store/index.js").ExtensionType;
@@ -39,12 +39,17 @@ class ParagraphLayoutPainter {
39
39
  console.warn('Expected paragraph layout but received different format:', layout);
40
40
  return;
41
41
  }
42
+ // Headings are not painted (TODO: fine-tune the baseline for heading
43
+ // sizes). Skipped on the block TYPE, not on the font size: H6 is set at
44
+ // the body's 15px (`HEADING_SCALE`), so a size test would paint it as text.
45
+ if (layout.paragraphType.startsWith('h'))
46
+ return;
42
47
  const renderedPositions = new Set();
43
48
  layout.sentences.forEach(sentence => {
44
49
  const fontSize = sentence.fontSize;
45
50
  const baselineY = getBaseline(fontSize);
46
51
  if (fontSize !== 15)
47
- return; // TODO: fine-tune for heading font sizes
52
+ return; // the baseline is tuned for body text only
48
53
  ctx.font = `${fontSize}px Inter`;
49
54
  ctx.strokeStyle = 'yellow';
50
55
  sentence.rects.forEach(textRect => {
@@ -4,7 +4,7 @@ import { addImages } from '../../../affine-block-image/index.js';
4
4
  import { CanvasRenderer, DefaultTool, EdgelessCRUDIdentifier, ExportManager, getSurfaceComponent, } from '../../../affine-block-surface/index.js';
5
5
  import { splitIntoLines } from '../../../affine-gfx-text/index.js';
6
6
  import { BookmarkStyles, DEFAULT_NOTE_HEIGHT, DEFAULT_NOTE_WIDTH, FrameBlockModel, MAX_IMAGE_WIDTH, } from '../../../affine-model/index.js';
7
- import { ClipboardAdapter, decodeClipboardBlobs, } from '../../../affine-shared/adapters/index.js';
7
+ import { ClipboardAdapter, decodeClipboardBlobs, ImageProxyService, } from '../../../affine-shared/adapters/index.js';
8
8
  import { CANVAS_EXPORT_IGNORE_TAGS, EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, } from '../../../affine-shared/consts/index.js';
9
9
  import { EmbedOptionProvider, ParseDocUrlProvider, TelemetryProvider, } from '../../../affine-shared/services/index.js';
10
10
  import { convertToPng, isInsidePageEditor, isTopLevelBlock, isUrlInClipboard, matchModels, referenceToNode, } from '../../../affine-shared/utils/index.js';
@@ -324,7 +324,7 @@ export class EdgelessClipboardController extends PageClipboard {
324
324
  }
325
325
  ctx.scale(dpr, dpr);
326
326
  const replaceImgSrcWithSvg = this._exportManager?.replaceImgSrcWithSvg;
327
- const imageProxy = host.std.clipboard.configs.get('imageProxy');
327
+ const imageProxy = host.std.get(ImageProxyService).imageProxyURL;
328
328
  const html2canvasOption = {
329
329
  ignoreElements: function (element) {
330
330
  if (CANVAS_EXPORT_IGNORE_TAGS.includes(element.tagName) ||
@@ -351,7 +351,7 @@ export class EdgelessClipboardController extends PageClipboard {
351
351
  await replaceImgSrcWithSvg?.(element);
352
352
  },
353
353
  backgroundColor: 'transparent',
354
- useCORS: imageProxy ? false : true,
354
+ useCORS: !imageProxy,
355
355
  proxy: imageProxy,
356
356
  };
357
357
  const _drawTopLevelBlock = async (block, isInFrame = false) => {
@@ -1,13 +1,33 @@
1
1
  import { KeymapExtension } from '../../std/index.js';
2
+ const NATIVE_FOCUSABLE_SELECTOR = 'button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
3
+ /**
4
+ * The editor host swallows Tab and Shift-Tab so that indentation stays under
5
+ * the control of the block-scoped handlers. That would however trap the focus
6
+ * on the native controls the editor renders (the collapse button of headings
7
+ * and lists, for instance), which then could neither be reached nor left with
8
+ * the keyboard. When the event originates from such a control — and not from
9
+ * editable text — the native tabbing behaviour is let through.
10
+ */
11
+ const isNativeFocusableTarget = (target) => {
12
+ if (!(target instanceof Element))
13
+ return false;
14
+ if (target instanceof HTMLElement && target.isContentEditable)
15
+ return false;
16
+ return !!target.closest(NATIVE_FOCUSABLE_SELECTOR);
17
+ };
2
18
  export const fallbackKeymap = KeymapExtension(() => {
3
19
  return {
4
20
  Tab: ctx => {
5
21
  const event = ctx.get('defaultState').event;
22
+ if (isNativeFocusableTarget(event.target))
23
+ return;
6
24
  event.stopPropagation();
7
25
  event.preventDefault();
8
26
  },
9
27
  'Shift-Tab': ctx => {
10
28
  const event = ctx.get('defaultState').event;
29
+ if (isNativeFocusableTarget(event.target))
30
+ return;
11
31
  event.stopPropagation();
12
32
  event.preventDefault();
13
33
  },
@@ -3,12 +3,14 @@ import { type BlockStdScope, type EditorHost } from '../../../std/index.js';
3
3
  import { GfxBlockElementModel, type GfxController, GfxPrimitiveElementModel } from '../../../std/gfx/index.js';
4
4
  import type { ExtensionType, Store } from '../../../store/index.js';
5
5
  import { CanvasRenderer } from '../../renderer/canvas-renderer.js';
6
- export type ExportOptions = {
7
- imageProxyEndpoint: string;
8
- };
9
6
  export declare class ExportManager {
10
7
  readonly std: BlockStdScope;
11
- private readonly _exportOptions;
8
+ /**
9
+ * The image proxy every remote-image fetch of the export goes through —
10
+ * resolved from {@link ImageProxyService}, the one host seam for it, never
11
+ * from a local constant. Empty means « fetch direct » (issue #258).
12
+ */
13
+ private get _imageProxyURL();
12
14
  replaceImgSrcWithSvg: (element: HTMLElement) => Promise<void>;
13
15
  get doc(): Store;
14
16
  get editorHost(): EditorHost;
@@ -1,6 +1,6 @@
1
1
  import { ImageBlockModel } from '../../../affine-model/index.js';
2
- import { FetchUtils } from '../../../affine-shared/adapters/index.js';
3
- import { CANVAS_EXPORT_IGNORE_TAGS, DEFAULT_IMAGE_PROXY_ENDPOINT, } from '../../../affine-shared/consts/index.js';
2
+ import { FetchUtils, ImageProxyService } from '../../../affine-shared/adapters/index.js';
3
+ import { CANVAS_EXPORT_IGNORE_TAGS } from '../../../affine-shared/consts/index.js';
4
4
  import { isInsidePageEditor, matchModels } from '../../../affine-shared/utils/index.js';
5
5
  import { BlockSuiteError, ErrorCode } from '../../../global/exceptions/index.js';
6
6
  import { deserializeXYWH } from '../../../global/gfx/index.js';
@@ -10,6 +10,14 @@ import { CanvasRenderer } from '../../renderer/canvas-renderer.js';
10
10
  import { getBgGridGap } from '../../utils/get-bg-grip-gap.js';
11
11
  import { FileExporter } from './file-exporter.js';
12
12
  export class ExportManager {
13
+ /**
14
+ * The image proxy every remote-image fetch of the export goes through —
15
+ * resolved from {@link ImageProxyService}, the one host seam for it, never
16
+ * from a local constant. Empty means « fetch direct » (issue #258).
17
+ */
18
+ get _imageProxyURL() {
19
+ return this.std.get(ImageProxyService).imageProxyURL;
20
+ }
13
21
  get doc() {
14
22
  return this.std.store;
15
23
  }
@@ -18,14 +26,11 @@ export class ExportManager {
18
26
  }
19
27
  constructor(std) {
20
28
  this.std = std;
21
- this._exportOptions = {
22
- imageProxyEndpoint: DEFAULT_IMAGE_PROXY_ENDPOINT,
23
- };
24
29
  this.replaceImgSrcWithSvg = async (element) => {
25
30
  const imgList = Array.from(element.querySelectorAll('img'));
26
31
  // Create an array of promises
27
32
  const promises = imgList.map(img => {
28
- return FetchUtils.fetchImage(img.src, undefined, this._exportOptions.imageProxyEndpoint)
33
+ return FetchUtils.fetchImage(img.src, undefined, this._imageProxyURL)
29
34
  .then(response => response && response.blob())
30
35
  .then(async (blob) => {
31
36
  if (!blob)
@@ -159,8 +164,8 @@ export class ExportManager {
159
164
  x: pageLeft - viewport.left,
160
165
  width: pageWidth,
161
166
  height: viewportHeight,
162
- useCORS: this._exportOptions.imageProxyEndpoint ? false : true,
163
- proxy: this._exportOptions.imageProxyEndpoint,
167
+ useCORS: !this._imageProxyURL,
168
+ proxy: this._imageProxyURL,
164
169
  };
165
170
  let data;
166
171
  try {
@@ -228,8 +233,8 @@ export class ExportManager {
228
233
  });
229
234
  await this.replaceImgSrcWithSvg(element);
230
235
  },
231
- useCORS: this._exportOptions.imageProxyEndpoint ? false : true,
232
- proxy: this._exportOptions.imageProxyEndpoint,
236
+ useCORS: !this._imageProxyURL,
237
+ proxy: this._imageProxyURL,
233
238
  };
234
239
  let data;
235
240
  try {
@@ -494,7 +494,10 @@ export interface FrameworkBackgroundDef {
494
494
  transitionBandWidth?: Ratio;
495
495
  chrome?: BackgroundChromeDef;
496
496
  }
497
- /** The default card: a plain white rectangle, no border, no radius. */
497
+ /**
498
+ * The default card: a plain rectangle in the shared notation scale's card
499
+ * fill, no border, no radius.
500
+ */
498
501
  export declare const DEFAULT_BACKGROUND_SURFACE: BackgroundSurfaceDef;
499
502
  /** The plot rectangle of a background of size `w × h`, in element-local units. */
500
503
  export declare function backgroundPlot(def: FrameworkBackgroundDef, w: number, h: number): {
@@ -1,6 +1,10 @@
1
- /** The default card: a plain white rectangle, no border, no radius. */
1
+ import { NOTATION_NEUTRALS } from '../../affine-shared/consts/index.js';
2
+ /**
3
+ * The default card: a plain rectangle in the shared notation scale's card
4
+ * fill, no border, no radius.
5
+ */
2
6
  export const DEFAULT_BACKGROUND_SURFACE = {
3
- fill: '#ffffff',
7
+ fill: NOTATION_NEUTRALS.cardFill,
4
8
  };
5
9
  /** The plot rectangle of a background of size `w × h`, in element-local units. */
6
10
  export function backgroundPlot(def, w, h) {
@@ -21,9 +21,9 @@ export class PriorityQueue {
21
21
  if (rightChildIndex < length) {
22
22
  leftChild = this.heap[leftChildIndex];
23
23
  rightChild = this.heap[rightChildIndex];
24
- if ((swap === null &&
24
+ if ((swap === -1 &&
25
25
  this._compare(rightChild.priority, element.priority) < 0) ||
26
- (swap !== null &&
26
+ (swap !== -1 &&
27
27
  this._compare(rightChild.priority, leftChild.priority) < 0)) {
28
28
  swap = rightChildIndex;
29
29
  }
@@ -6,6 +6,11 @@ export declare class ToggleButton extends ToggleButton_base {
6
6
  render(): import("lit-html").TemplateResult<1>;
7
7
  accessor collapsed: boolean;
8
8
  accessor updateCollapsed: (collapsed: boolean) => void;
9
+ /**
10
+ * Id of the children container this button expands and collapses,
11
+ * exposed to assistive technologies through `aria-controls`.
12
+ */
13
+ accessor controls: string;
9
14
  }
10
15
  declare global {
11
16
  interface HTMLElementTagNameMap {
@@ -48,13 +48,18 @@ let ToggleButton = (() => {
48
48
  let _updateCollapsed_decorators;
49
49
  let _updateCollapsed_initializers = [];
50
50
  let _updateCollapsed_extraInitializers = [];
51
+ let _controls_decorators;
52
+ let _controls_initializers = [];
53
+ let _controls_extraInitializers = [];
51
54
  return class ToggleButton extends _classSuper {
52
55
  static {
53
56
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
54
57
  _collapsed_decorators = [property({ attribute: false })];
55
58
  _updateCollapsed_decorators = [property({ attribute: false })];
59
+ _controls_decorators = [property({ attribute: false })];
56
60
  __esDecorate(this, null, _collapsed_decorators, { kind: "accessor", name: "collapsed", static: false, private: false, access: { has: obj => "collapsed" in obj, get: obj => obj.collapsed, set: (obj, value) => { obj.collapsed = value; } }, metadata: _metadata }, _collapsed_initializers, _collapsed_extraInitializers);
57
61
  __esDecorate(this, null, _updateCollapsed_decorators, { kind: "accessor", name: "updateCollapsed", static: false, private: false, access: { has: obj => "updateCollapsed" in obj, get: obj => obj.updateCollapsed, set: (obj, value) => { obj.updateCollapsed = value; } }, metadata: _metadata }, _updateCollapsed_initializers, _updateCollapsed_extraInitializers);
62
+ __esDecorate(this, null, _controls_decorators, { kind: "accessor", name: "controls", static: false, private: false, access: { has: obj => "controls" in obj, get: obj => obj.controls, set: (obj, value) => { obj.controls = value; } }, metadata: _metadata }, _controls_initializers, _controls_extraInitializers);
58
63
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
59
64
  }
60
65
  static { this.styles = css `
@@ -63,6 +68,11 @@ let ToggleButton = (() => {
63
68
  align-items: start;
64
69
  justify-content: start;
65
70
  position: absolute;
71
+ padding: 0;
72
+ border: 0;
73
+ color: inherit;
74
+ background: transparent;
75
+ font: inherit;
66
76
  width: 16px;
67
77
  height: 16px;
68
78
  top: calc((1em - 16px) / 2 + 5px);
@@ -78,6 +88,11 @@ let ToggleButton = (() => {
78
88
  background: var(--affine-hover-color);
79
89
  }
80
90
 
91
+ .toggle-icon:focus-visible {
92
+ opacity: 1;
93
+ outline: 1px solid var(--affine-primary-color);
94
+ }
95
+
81
96
  .toggle-icon[data-collapsed='true'] {
82
97
  opacity: 1;
83
98
  }
@@ -100,32 +115,23 @@ let ToggleButton = (() => {
100
115
  }
101
116
  `; }
102
117
  render() {
103
- const toggleDownTemplate = html `
104
- <div
105
- contenteditable="false"
106
- class="toggle-icon"
107
- @click=${() => this.updateCollapsed(!this.collapsed)}
108
- >
109
- ${ToggleDownIcon({
110
- width: '16px',
111
- height: '16px',
112
- })}
113
- </div>
114
- `;
115
- const toggleRightTemplate = html `
116
- <div
118
+ return html `
119
+ <button
120
+ type="button"
117
121
  contenteditable="false"
118
122
  class="toggle-icon"
119
123
  data-collapsed=${this.collapsed}
124
+ aria-label=${this.collapsed ? 'Expand content' : 'Collapse content'}
125
+ aria-expanded=${!this.collapsed}
126
+ aria-controls=${this.controls}
120
127
  @click=${() => this.updateCollapsed(!this.collapsed)}
121
128
  >
122
- ${ToggleRightIcon({
129
+ ${(this.collapsed ? ToggleRightIcon : ToggleDownIcon)({
123
130
  width: '16px',
124
131
  height: '16px',
125
132
  })}
126
- </div>
133
+ </button>
127
134
  `;
128
- return this.collapsed ? toggleRightTemplate : toggleDownTemplate;
129
135
  }
130
136
  #collapsed_accessor_storage = __runInitializers(this, _collapsed_initializers, void 0);
131
137
  get collapsed() { return this.#collapsed_accessor_storage; }
@@ -133,9 +139,16 @@ let ToggleButton = (() => {
133
139
  #updateCollapsed_accessor_storage = (__runInitializers(this, _collapsed_extraInitializers), __runInitializers(this, _updateCollapsed_initializers, void 0));
134
140
  get updateCollapsed() { return this.#updateCollapsed_accessor_storage; }
135
141
  set updateCollapsed(value) { this.#updateCollapsed_accessor_storage = value; }
142
+ #controls_accessor_storage = (__runInitializers(this, _updateCollapsed_extraInitializers), __runInitializers(this, _controls_initializers, void 0));
143
+ /**
144
+ * Id of the children container this button expands and collapses,
145
+ * exposed to assistive technologies through `aria-controls`.
146
+ */
147
+ get controls() { return this.#controls_accessor_storage; }
148
+ set controls(value) { this.#controls_accessor_storage = value; }
136
149
  constructor() {
137
150
  super(...arguments);
138
- __runInitializers(this, _updateCollapsed_extraInitializers);
151
+ __runInitializers(this, _controls_extraInitializers);
139
152
  }
140
153
  };
141
154
  })();
@@ -1,18 +1,24 @@
1
1
  import { ConnectorMode, FontFamily, FontWeight, PointStyle, ShapeStyle, StrokeStyle, TextAlign, } from '../../affine-model/index.js';
2
+ import { NOTATION_NEUTRALS } from '../../affine-shared/consts/index.js';
2
3
  import { makeTemplateSnapshot, surfaceText, } from '../make-snapshot.js';
3
4
  /**
4
5
  * The generic ("Other") diagrams: built ONLY from general BlockSuite shapes
5
6
  * (`shape` rect/polygon, `text`, `connector`) per the composition principle —
6
7
  * they belong to no framework, so they ship from the template package itself.
7
8
  */
8
- const DARK = '#262626';
9
- const MUTED = '#9aa0a6';
9
+ /**
10
+ * Their neutrals are the shared notation scale's, like every framework's:
11
+ * the ink, the divider grey, the label grey and the card white. Only
12
+ * the hues (kanban cards, gantt bars) are the diagrams' own.
13
+ */
14
+ const DARK = NOTATION_NEUTRALS.ink;
15
+ const MUTED = NOTATION_NEUTRALS.divider;
10
16
  function rect(x, y, w, h, opts = {}) {
11
17
  const el = {
12
18
  type: 'shape',
13
19
  shapeType: opts.shapeType ?? 'rect',
14
20
  filled: true,
15
- fillColor: opts.fill ?? '#ffffff',
21
+ fillColor: opts.fill ?? NOTATION_NEUTRALS.cardFill,
16
22
  strokeColor: opts.stroke ?? DARK,
17
23
  strokeWidth: opts.sw ?? 2,
18
24
  strokeStyle: opts.dash ? StrokeStyle.Dash : StrokeStyle.Solid,
@@ -36,7 +42,7 @@ function label(x, y, w, h, str, opts = {}) {
36
42
  return {
37
43
  type: 'text',
38
44
  text: surfaceText(str),
39
- color: opts.color ?? '#1a1a1a',
45
+ color: opts.color ?? DARK,
40
46
  fontFamily: FontFamily.Inter,
41
47
  fontSize: opts.fontSize ?? 16,
42
48
  fontWeight: opts.weight ?? FontWeight.Regular,
@@ -72,7 +78,12 @@ function swot() {
72
78
  }
73
79
  // ── Kanban (To do / Doing / Done) ─────────────────────────────────────
74
80
  function kanban() {
75
- const colOpts = { fill: '#f4f4f5', stroke: MUTED, sw: 1.5, radius: 10 };
81
+ const colOpts = {
82
+ fill: NOTATION_NEUTRALS.cardFill,
83
+ stroke: MUTED,
84
+ sw: 1.5,
85
+ radius: 10,
86
+ };
76
87
  const head = {
77
88
  fontSize: 18,
78
89
  weight: FontWeight.Medium,
@@ -109,7 +120,10 @@ function bmc() {
109
120
  });
110
121
  const hdr = (x, s) => ({
111
122
  box: rect(x, 8, 128, 34, { stroke: MUTED, sw: 1 }),
112
- txt: label(x + 8, 16, 120, 18, s, { fontSize: 11, color: '#5f6368' }),
123
+ txt: label(x + 8, 16, 120, 18, s, {
124
+ fontSize: 11,
125
+ color: NOTATION_NEUTRALS.label,
126
+ }),
113
127
  });
114
128
  const h1 = hdr(470, 'Designed for');
115
129
  const h2 = hdr(602, 'Designed by');
@@ -156,7 +170,7 @@ function fishbone() {
156
170
  sw: 1.4,
157
171
  dash: true,
158
172
  text: n,
159
- textColor: '#5f6368',
173
+ textColor: NOTATION_NEUTRALS.label,
160
174
  fontSize: 13,
161
175
  });
162
176
  const out = {
@@ -190,10 +204,13 @@ function gantt() {
190
204
  // week gridlines + labels
191
205
  for (let i = 0; i < 6; i++) {
192
206
  const x = 220 + i * 130;
193
- out[`g${i}`] = line(x, 40, x, 268, { stroke: '#e0e0e0', sw: 1 });
207
+ out[`g${i}`] = line(x, 40, x, 268, {
208
+ stroke: NOTATION_NEUTRALS.cardBorder,
209
+ sw: 1,
210
+ });
194
211
  out[`w${i}`] = label(x - 16, 12, 40, 20, `W${i + 1}`, {
195
212
  fontSize: 12,
196
- color: '#5f6368',
213
+ color: NOTATION_NEUTRALS.label,
197
214
  align: TextAlign.Center,
198
215
  });
199
216
  }
@@ -212,11 +229,11 @@ function gantt() {
212
229
  }
213
230
  const ATTRS = 'width="100%" height="100%" viewBox="0 0 135 80" xmlns="http://www.w3.org/2000/svg"';
214
231
  const previews = {
215
- swot: `<svg ${ATTRS} fill="none"><rect x="20" y="12" width="95" height="56" stroke="#262626" stroke-width="2"/><path d="M67.5 12 V68 M20 40 H115" stroke="#262626" stroke-width="1.6"/></svg>`,
216
- kanban: `<svg ${ATTRS} fill="none"><rect x="10" y="12" width="35" height="56" rx="4" stroke="#9aa0a6"/><rect x="50" y="12" width="35" height="56" rx="4" stroke="#9aa0a6"/><rect x="90" y="12" width="35" height="56" rx="4" stroke="#9aa0a6"/><rect x="15" y="22" width="25" height="11" rx="2" fill="#fde6c8"/><rect x="55" y="22" width="25" height="11" rx="2" fill="#d6e4fb"/><rect x="95" y="22" width="25" height="11" rx="2" fill="#d5efd9"/></svg>`,
217
- bmc: `<svg ${ATTRS} fill="none"><g stroke="#262626" stroke-width="1.2"><rect x="8" y="14" width="22" height="40"/><rect x="32" y="14" width="22" height="20"/><rect x="32" y="35" width="22" height="19"/><rect x="56" y="14" width="22" height="40"/><rect x="80" y="14" width="22" height="20"/><rect x="80" y="35" width="22" height="19"/><rect x="104" y="14" width="22" height="40"/><rect x="8" y="56" width="57" height="14"/><rect x="68" y="56" width="58" height="14"/></g></svg>`,
218
- fishbone: `<svg ${ATTRS} fill="none"><path d="M14 40 H112" stroke="#262626" stroke-width="3"/><rect x="112" y="33" width="20" height="14" stroke="#262626" stroke-width="1.4"/><path d="M40 18 L52 40 M40 62 L52 40 M84 18 L96 40 M84 62 L96 40" stroke="#262626" stroke-width="1.4"/></svg>`,
219
- gantt: `<svg ${ATTRS} fill="none"><path d="M40 14 V70 M62 14 V70 M84 14 V70 M106 14 V70" stroke="#e0e0e0"/><rect x="40" y="22" width="34" height="8" rx="2" fill="#4574c4"/><rect x="52" y="36" width="44" height="8" rx="2" fill="#2f9e95"/><rect x="62" y="50" width="50" height="8" rx="2" fill="#d99a2b"/><rect x="84" y="64" width="28" height="8" rx="2" fill="#43a06b"/></svg>`,
232
+ swot: `<svg ${ATTRS} fill="none"><rect x="20" y="12" width="95" height="56" stroke="${DARK}" stroke-width="2"/><path d="M67.5 12 V68 M20 40 H115" stroke="${DARK}" stroke-width="1.6"/></svg>`,
233
+ kanban: `<svg ${ATTRS} fill="none"><rect x="10" y="12" width="35" height="56" rx="4" stroke="${MUTED}"/><rect x="50" y="12" width="35" height="56" rx="4" stroke="${MUTED}"/><rect x="90" y="12" width="35" height="56" rx="4" stroke="${MUTED}"/><rect x="15" y="22" width="25" height="11" rx="2" fill="#fde6c8"/><rect x="55" y="22" width="25" height="11" rx="2" fill="#d6e4fb"/><rect x="95" y="22" width="25" height="11" rx="2" fill="#d5efd9"/></svg>`,
234
+ bmc: `<svg ${ATTRS} fill="none"><g stroke="${DARK}" stroke-width="1.2"><rect x="8" y="14" width="22" height="40"/><rect x="32" y="14" width="22" height="20"/><rect x="32" y="35" width="22" height="19"/><rect x="56" y="14" width="22" height="40"/><rect x="80" y="14" width="22" height="20"/><rect x="80" y="35" width="22" height="19"/><rect x="104" y="14" width="22" height="40"/><rect x="8" y="56" width="57" height="14"/><rect x="68" y="56" width="58" height="14"/></g></svg>`,
235
+ fishbone: `<svg ${ATTRS} fill="none"><path d="M14 40 H112" stroke="${DARK}" stroke-width="3"/><rect x="112" y="33" width="20" height="14" stroke="${DARK}" stroke-width="1.4"/><path d="M40 18 L52 40 M40 62 L52 40 M84 18 L96 40 M84 62 L96 40" stroke="${DARK}" stroke-width="1.4"/></svg>`,
236
+ gantt: `<svg ${ATTRS} fill="none"><path d="M40 14 V70 M62 14 V70 M84 14 V70 M106 14 V70" stroke="${NOTATION_NEUTRALS.cardBorder}"/><rect x="40" y="22" width="34" height="8" rx="2" fill="#4574c4"/><rect x="52" y="36" width="44" height="8" rx="2" fill="#2f9e95"/><rect x="62" y="50" width="50" height="8" rx="2" fill="#d99a2b"/><rect x="84" y="64" width="28" height="8" rx="2" fill="#43a06b"/></svg>`,
220
237
  };
221
238
  function t(name, preview, elements) {
222
239
  return {
@@ -18,4 +18,7 @@ export declare const UnderthroughExtension: ExtensionType & {
18
18
  export declare const CodeExtension: ExtensionType & {
19
19
  identifier: import("../global/di/types.js").ServiceIdentifier<import("../std/inline/index.js").InlineMarkdownMatch<AffineTextAttributes>>;
20
20
  };
21
+ export declare const EmDashExtension: ExtensionType & {
22
+ identifier: import("../global/di/types.js").ServiceIdentifier<import("../std/inline/index.js").InlineMarkdownMatch<AffineTextAttributes>>;
23
+ };
21
24
  export declare const MarkdownExtensions: ExtensionType[];
@@ -193,6 +193,24 @@ export const CodeExtension = InlineMarkdownExtension({
193
193
  });
194
194
  },
195
195
  });
196
+ // typographic replacement: word -- + space => word — + space
197
+ // not convert: --- + space (divider shortcut), --flag + space, inside inline code
198
+ export const EmDashExtension = InlineMarkdownExtension({
199
+ name: 'em-dash',
200
+ pattern: /(?:^|[^-])--\s$/,
201
+ action: ({ inlineEditor, inlineRange, undoManager }) => {
202
+ const dashes = { index: inlineRange.index - 3, length: 2 };
203
+ const format = inlineEditor.getFormat(dashes);
204
+ if (format.code)
205
+ return;
206
+ undoManager.stopCapturing();
207
+ inlineEditor.insertText(dashes, '—', format);
208
+ inlineEditor.setInlineRange({
209
+ index: inlineRange.index - 1,
210
+ length: 0,
211
+ });
212
+ },
213
+ });
196
214
  export const MarkdownExtensions = [
197
215
  BoldItalicMarkdown,
198
216
  BoldMarkdown,
@@ -201,4 +219,5 @@ export const MarkdownExtensions = [
201
219
  UnderthroughExtension,
202
220
  CodeExtension,
203
221
  LatexExtension,
222
+ EmDashExtension,
204
223
  ];
@@ -2,7 +2,17 @@ import type { TransformerMiddleware } from '../../../store/index.js';
2
2
  import { StoreExtension } from '../../../store/index.js';
3
3
  export declare const customImageProxyMiddleware: (imageProxyURL: string) => TransformerMiddleware;
4
4
  export declare const setImageProxyMiddlewareURL: (url: string) => void;
5
+ /**
6
+ * Reads the URL at run time: a `setImageProxyURL` made after module load
7
+ * reaches every job using this middleware.
8
+ */
5
9
  export declare const defaultImageProxyMiddleware: TransformerMiddleware;
10
+ /**
11
+ * The ONE seam governing every remote-image fetch the library performs on the
12
+ * host's behalf: link-card favicons and og:images, image import, canvas
13
+ * PNG/PDF export, copy-as-image. An empty URL means « fetch direct ».
14
+ * See `docs/integrate/04-host-seams.md`.
15
+ */
6
16
  export declare class ImageProxyService extends StoreExtension {
7
17
  static key: string;
8
18
  private _imageProxyURL;