Skip to content

Commit

Permalink
✨Introduce API to create text spans
Browse files Browse the repository at this point in the history
This commit introduces the function `span()` to create text spans more
conveniently. Using this function provides better tool support since the
tooling can suggest text properties and values. Since the function
returns objects with a specific type, less type annotations are
required.

For example, the following line of code

```ts
let block = { text: ['Hello ', { text: 'World!', fontWeight: 'bold' }] };
```

can now be replaced with:

```ts
let block = { text: ['Hello ', span('World!', { fontWeight: 'bold' })]);
```
  • Loading branch information
ralfstx committed Oct 5, 2024
1 parent 102c9a5 commit 189fc3b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Minimum requirements bumped to Node 20 and npm 10.
- The functions `line()`, `rect()`, `circle()`, and `path()` to create
graphics shapes with less code and better tool support.

- The function `span()` to create text spans with less code and better
tool support.

### Deprecated

- `TextAttrs` in favor of `TextProps`.
Expand Down
44 changes: 44 additions & 0 deletions src/api/text.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import crypto from 'node:crypto';

import { describe, expect, it } from 'vitest';

import { span } from './text.ts';

global.crypto ??= (crypto as any).webcrypto;

describe('test', () => {
describe('span', () => {
it('creates text span with given string', () => {
const sp = span('foo');

expect(sp).toEqual({ text: 'foo' });
});

it('creates text span with given string and props', () => {
const sp = span('foo', { fontStyle: 'italic' });

expect(sp).toEqual({ text: 'foo', fontStyle: 'italic' });
});

it('creates text span with given array and props', () => {
const sp = span(['foo', span('bar', { fontStyle: 'italic' })], { fontSize: 8 });

expect(sp).toEqual({ text: ['foo', { text: 'bar', fontStyle: 'italic' }], fontSize: 8 });
});

it('extracts a single array element in text', () => {
const sp = span(['foo'], { fontStyle: 'italic' });

expect(sp).toEqual({ text: 'foo', fontStyle: 'italic' });
});

it('merges a single text span in text, inner span takes precedence', () => {
const sp = span(span('foo', { fontWeight: 'bold' }), {
fontStyle: 'italic',
fontWeight: 'normal',
});

expect(sp).toEqual({ text: 'foo', fontWeight: 'bold', fontStyle: 'italic' });
});
});
});
14 changes: 14 additions & 0 deletions src/api/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ export type Text = string | TextSpan | TextSpan[];
*/
export type TextSpan = { text: string | TextSpan | (string | TextSpan)[] } & TextProps;

/**
* Creates a span of text with the given text and properties.
*
* @param text The text to display in this span.
* @param props Optional properties for the span.
*/
export function span(text: string | TextSpan | (string | TextSpan)[], props?: TextProps): TextSpan {
const unwrappedText = Array.isArray(text) && text.length === 1 ? text[0] : text;
if (typeof unwrappedText === 'string' || Array.isArray(unwrappedText)) {
return { ...props, text: unwrappedText };
}
return { ...props, ...unwrappedText };
}

/**
* The font weight is an integer between 0 and 1000. The keywords
* `normal` (400) and `bold` (700) are also supported.
Expand Down

0 comments on commit 189fc3b

Please sign in to comment.