Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion blocksuite/affine/blocks/note/src/configs/slash-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ const noteSlashMenuConfig: SlashMenuConfig = {
],
};

/**
* Create a slash-menu action item that converts the current block to a specified text flavour and type.
*
* @param config - Configuration describing the conversion target (includes name, flavour, type, icon, description, and optional `searchAlias`).
* @param group - Optional menu group identifier to place the action under.
* @returns A SlashMenuActionItem that is shown only if the target flavour exists in the schema and, when invoked, updates the current block to the configured flavour and type.
*/
function createConversionItem(
config: TextConversionConfig,
group?: SlashMenuItem['group']
Expand Down Expand Up @@ -153,4 +160,4 @@ function createTextFormatItem(
export const NoteSlashMenuConfigExtension = SlashMenuConfigExtension(
'affine:note',
noteSlashMenuConfig
);
);
28 changes: 25 additions & 3 deletions blocksuite/affine/data-view/src/core/group-by/compare-date-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ export const RELATIVE_ASC = [
export const RELATIVE_DESC = [...RELATIVE_ASC].reverse();

/**
* Sorts relative date keys in chronological order
* Orders two relative date keys according to a predefined chronological sequence.
*
* @param a - First key to compare.
* @param b - Second key to compare.
* @param asc - When true, use ascending chronological order; when false, use descending order.
* @returns A negative number if `a` comes before `b`, a positive number if `a` comes after `b`, or `0` if their order is undefined.
*/
export function sortRelativeKeys(a: string, b: string, asc: boolean): number {
const order: readonly string[] = asc ? RELATIVE_ASC : RELATIVE_DESC;
Expand All @@ -25,7 +30,15 @@ export function sortRelativeKeys(a: string, b: string, asc: boolean): number {
}

/**
* Sorts numeric date keys (timestamps)
* Compare two strings that represent numeric date keys by their numeric value.
*
* If both inputs convert to finite numbers the result orders them ascending when `asc` is true,
* otherwise descending. If either input is not numeric, no ordering is applied.
*
* @param a - First key string, expected to contain a numeric timestamp
* @param b - Second key string, expected to contain a numeric timestamp
* @param asc - When true, sort in ascending numeric order; when false, sort in descending numeric order
* @returns A negative number if `a` should come before `b`, a positive number if `a` should come after `b`, `0` if they are equal or either value is not numeric
*/
export function sortNumericKeys(a: string, b: string, asc: boolean): number {
const na = Number(a);
Expand All @@ -38,6 +51,15 @@ export function sortNumericKeys(a: string, b: string, asc: boolean): number {
return 0; // Not both numeric
}

/**
* Create a comparator for date-like string keys that orders relative keys, numeric keys, and plain strings according to the chosen mode and direction.
*
* When `mode` is `'date-relative'`, relative keys are ordered by a predefined chronological list first, then numeric-like keys by their numeric value, and finally by lexicographic order for remaining ties. For other modes, numeric-like keys are compared first, then lexicographically.
*
* @param mode - If `'date-relative'` use relative-key-first ordering; any other value uses numeric-first ordering.
* @param asc - If `true` sort ascending; if `false` sort descending.
* @returns A comparator function that returns a negative number if `a` should come before `b`, `0` if they are equivalent, or a positive number if `a` should come after `b`.
*/
export function compareDateKeys(mode: string | undefined, asc: boolean) {
return (a: string, b: string) => {
if (mode === 'date-relative') {
Expand All @@ -59,4 +81,4 @@ export function compareDateKeys(mode: string | undefined, asc: boolean) {
(asc ? a.localeCompare(b) : b.localeCompare(a))
);
};
}
}
10 changes: 9 additions & 1 deletion blocksuite/affine/data-view/src/core/group-by/define.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ const WEEK_OPTS_SUN = { weekStartsOn: 0 } as const;
const rangeLabel = (a: Date, b: Date) =>
`${fmt(a, 'MMM d yyyy')} – ${fmt(b, 'MMM d yyyy')}`;

/**
* Creates a date-focused GroupByConfig with common wiring for grouping and labeling dates.
*
* @param name - Identifier for the resulting group configuration
* @param grouper - Maps a date (milliseconds or null) to one or more group entries with `key` and numeric `value` (or `null` for ungrouped)
* @param groupName - Produces the display label for a group's numeric value (or `null` for ungrouped)
* @returns A GroupByConfig configured for date grouping and rendered with the date group view
*/
function buildDateCfg(
name: string,
grouper: (ms: number | null) => { key: string; value: number | null }[],
Expand Down Expand Up @@ -263,4 +271,4 @@ export const groupByMatchers: GroupByConfig[] = [
dateWeekMonCfg,
dateMonthCfg,
dateYearCfg,
];
];
8 changes: 7 additions & 1 deletion blocksuite/affine/data-view/src/core/group-by/trait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ export class Group<
}
}

/**
* Type guard that detects objects having an optional `groupProperties` array.
*
* @param data - Value to test for a `groupProperties` property
* @returns `true` if `data` is an object with a `groupProperties` property that is either `undefined` or an array of `GroupProperty`; `false` otherwise.
*/
function hasGroupProperties(
data: unknown
): data is { groupProperties?: GroupProperty[] } {
Expand Down Expand Up @@ -496,4 +502,4 @@ export const sortByManually = <T>(
}
result.push(...map.values());
return result;
};
};
9 changes: 7 additions & 2 deletions blocksuite/affine/shared/src/adapters/pdf/css-utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
/**
* Resolve CSS variable color (var(--affine-xxx)) using computed styles
* Resolve a CSS custom property reference of the form `var(--name)` to its computed value from the document root.
*
* Accepts a CSS color string or a `var(...)` expression. If the input is a plain value (not a `var(...)` expression), it is returned unchanged.
*
* @param color - A CSS color string or a `var(...)` reference to a CSS custom property.
* @returns `null` if the input is falsy, not a string, the environment lacks a `document`, the input is not a valid `var(...)` reference, the referenced name does not start with `--`, or the computed value is empty; otherwise the trimmed computed value of the CSS custom property.
*/
export function resolveCssVariable(color: string): string | null {
if (!color || typeof color !== 'string') {
Expand All @@ -22,4 +27,4 @@ export function resolveCssVariable(color: string): string | null {
}
const value = rootComputedStyle.getPropertyValue(variable).trim();
return value || null;
}
}
10 changes: 6 additions & 4 deletions blocksuite/affine/shared/src/adapters/pdf/delta-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import { resolveCssVariable } from './css-utils.js';

/**
* Extract text from delta operations, preserving inline properties
* Returns normalized format: string if simple, array if complex (with inline styles)
*/
* Convert a Quill-style delta (props.text.delta) into a normalized text representation with inline styling.
*
* @param props - Input object expected to contain a Quill-like delta at `props.text.delta`.
* @param configs - Map of configuration values; supports `docLinkBaseUrl` for constructing reference links and `title:<pageId>` entries to supply display titles for referenced pages.
* @returns A single space when no renderable content is present; a plain string when the result is a single unstyled segment; otherwise an array of strings and objects. Objects include a `text` property and optional inline styling fields such as `bold`, `italics`, `decoration`, `font`, `fontSize`, `color`, `background`, and `link`.
export function extractTextWithInline(
props: Record<string, any>,
configs: Map<string, string>
Expand Down Expand Up @@ -119,4 +121,4 @@
return result[0] || ' ';
}
return result;
}
}

Check failure on line 124 in blocksuite/affine/shared/src/adapters/pdf/delta-converter.ts

View workflow job for this annotation

GitHub Actions / Typecheck

'*/' expected.
22 changes: 18 additions & 4 deletions blocksuite/affine/shared/src/adapters/pdf/image-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
import { MAX_PAPER_HEIGHT, MAX_PAPER_WIDTH } from './utils.js';

/**
* Calculate image dimensions respecting props, original size, and paper constraints
* Compute target image width and height using provided block dimensions or fallbacks to original dimensions, then clamp to paper size limits preserving aspect ratio when necessary.
*
* @param blockWidth - Preferred width from layout; used if > 0
* @param blockHeight - Preferred height from layout; used if > 0
* @param originalWidth - Source image intrinsic width; used when `blockWidth` is not provided
* @param originalHeight - Source image intrinsic height; used when `blockHeight` is not provided
* @returns An object containing `width` and/or `height` (numbers) representing the computed dimensions; empty object if neither dimension can be determined
*/
export function calculateImageDimensions(
blockWidth: number | undefined,
Expand Down Expand Up @@ -54,7 +60,12 @@ export function calculateImageDimensions(
}

/**
* Extract dimensions from SVG
* Parse an SVG source string and extract numeric width and height.
*
* If `width` or `height` attributes are missing, attempt to derive them from the SVG `viewBox`'s width and height when available.
*
* @param svgText - The SVG document text to parse
* @returns An object containing numeric `width` and/or `height` when found; properties are `undefined` if not present or not derivable
*/
export function extractSvgDimensions(svgText: string): {
width?: number;
Expand Down Expand Up @@ -87,7 +98,10 @@ export function extractSvgDimensions(svgText: string): {
}

/**
* Extract dimensions from JPEG/PNG using Image API
* Extract the intrinsic width and height in pixels from an image Blob.
*
* @param blob - Image file blob (e.g., JPEG or PNG)
* @returns An object with `width` and `height` in pixels when available, or an empty object if dimensions could not be determined
*/
export async function extractImageDimensions(
blob: Blob
Expand All @@ -111,4 +125,4 @@ export async function extractImageDimensions(
};
img.src = url;
});
}
}
17 changes: 13 additions & 4 deletions blocksuite/affine/shared/src/adapters/pdf/svg-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import { resolveCssVariable } from './css-utils.js';

/**
* Get SVG string for bulleted list icon based on depth
* Selects a bulleted list SVG icon variant based on list depth.
*
* @param depth - List nesting depth used to choose one of four bullet variants
* @returns The SVG markup for the selected bullet icon as a string
*/
export function getBulletIconSvg(depth: number): string {
const bulletIndex = depth % 4;
Expand All @@ -20,7 +23,10 @@ export function getBulletIconSvg(depth: number): string {
}

/**
* Get SVG string for checkbox icon (checked or unchecked)
* Return the SVG markup for a checkbox icon that reflects the checked state.
*
* @param checked - If `true`, returns the filled (checked) checkbox SVG; if `false`, returns the outlined (unchecked) checkbox SVG
* @returns The SVG markup string for the checkbox icon
*/
export function getCheckboxIconSvg(checked: boolean): string {
if (checked) {
Expand All @@ -31,12 +37,15 @@ export function getCheckboxIconSvg(checked: boolean): string {
}

/**
* Get SVG string for toggle icon (down or right)
* Provide an SVG chevron icon that reflects a toggle's expansion state.
*
* @param expanded - Whether the toggle is expanded; when true the icon is a downward-pointing chevron, otherwise a right-pointing chevron.
* @returns An SVG string representing a downward-pointing chevron when `expanded` is `true`, or a right-pointing chevron when `expanded` is `false`.
*/
export function getToggleIconSvg(expanded: boolean): string {
if (expanded) {
return '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path d="M7.41 8.59L12 13.17L16.59 8.59L18 10L12 16L6 10L7.41 8.59Z" fill="#666666"/></svg>';
} else {
return '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12L8.59 7.41L10 6L16 12L10 18L8.59 16.59Z" fill="#666666"/></svg>';
}
}
}
17 changes: 13 additions & 4 deletions blocksuite/affine/shared/src/adapters/pdf/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,20 @@ export const TABLE_LAYOUT_NO_BORDERS = {
} as const;

/**
* Generate placeholder text for images that cannot be rendered
* Create a fallback placeholder label for an image.
*
* @param caption - Optional caption to include in the placeholder
* @returns `"[Image: {caption}]"` if `caption` is provided, `"[Image]"` otherwise
*/
export function getImagePlaceholder(caption?: string): string {
return caption ? `[Image: ${caption}]` : '[Image]';
}

/**
* Check if text content has meaningful content
* Determine whether provided text content contains any non-empty text.
*
* @param textContent - A string or an array of strings or objects with a `text` property. When a string is provided, whitespace-only strings are treated as empty. When an array is provided, presence is determined by the array having at least one element.
* @returns `true` if the content contains text (a string with non-whitespace characters or an array with at least one item), `false` otherwise.
*/
export function hasTextContent(
textContent: string | Array<string | { text: string; [key: string]: any }>
Expand All @@ -57,7 +63,10 @@ export function hasTextContent(
}

/**
* Convert text content array to plain string
* Convert mixed text content into a single plain string.
*
* @param textContent - A string or an array containing strings or objects with a `text` property; when an array is provided, each element's string or `text` value is used in order.
* @returns The concatenated plain string produced from the input.
*/
export function textContentToString(
textContent: string | Array<string | { text: string; [key: string]: any }>
Expand All @@ -68,4 +77,4 @@ export function textContentToString(
return textContent
.map(item => (typeof item === 'string' ? item : item.text))
.join('');
}
}
15 changes: 13 additions & 2 deletions blocksuite/affine/shared/src/utils/number-prefix.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* Converts a non-negative integer into a lowercase alphabetic sequence using `a`..`z`.
*
* @param n - The non-negative integer to convert (0 maps to `a`)
* @returns The lowercase alphabetic representation where `0` → `a`, `1` → `b`, and `26` → `aa`
*/
function number2letter(n: number) {
const ordA = 'a'.charCodeAt(0);
const ordZ = 'z'.charCodeAt(0);
Expand All @@ -10,7 +16,12 @@ function number2letter(n: number) {
return s;
}

// Derive from https://gist.github.com/imilu/00f32c61e50b7ca296f91e9d96d8e976
/**
* Convert a positive integer to its Roman numeral representation.
*
* @param num - The integer to convert; expected to be positive (values ≤ 0 produce an empty string)
* @returns The Roman numeral representation of `num` using standard symbols (e.g., `M`, `CM`, `D`, `CD`, `C`, `XC`, `L`, `XL`, `X`, `IX`, `V`, `IV`, `I`)
*/
function number2roman(num: number) {
const lookup: Record<string, number> = {
M: 1000,
Expand Down Expand Up @@ -50,4 +61,4 @@ function getPrefix(depth: number, index: number) {
export function getNumberPrefix(index: number, depth: number) {
const prefix = getPrefix(depth, index);
return `${prefix}.`;
}
}
7 changes: 6 additions & 1 deletion blocksuite/affine/widgets/linked-doc/src/transformers/pdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import type { Store } from '@blocksuite/store';

import { download } from './utils.js';

/**
* Export the given document to a PDF file and trigger a download of the generated file.
*
* @param doc - The document store to export; its workspace data and provider are used to build the transformer, produce a snapshot, and generate the PDF
*/
async function exportDoc(doc: Store) {
const provider = doc.provider;
const job = doc.getTransformer([
Expand All @@ -29,4 +34,4 @@ async function exportDoc(doc: Store) {

export const PdfTransformer = {
exportDoc,
};
};
Loading
Loading