afformative 0.6.3 → 0.7.0-beta.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.
- package/README.md +101 -102
- package/dist/index.cjs +15 -0
- package/dist/index.d.cts +33 -0
- package/dist/index.d.mts +33 -0
- package/dist/index.mjs +14 -0
- package/package.json +41 -12
- package/dist/afformative.cjs.js +0 -61
- package/dist/afformative.esm.js +0 -53
- package/dist/afformative.umd.js +0 -96
- package/dist/afformative.umd.min.js +0 -1
- package/dist/types/index.d.ts +0 -2
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/makeFormatter.d.ts +0 -97
- package/dist/types/makeFormatter.d.ts.map +0 -1
- package/src/index.ts +0 -1
- package/src/makeFormatter.test.ts +0 -218
- package/src/makeFormatter.ts +0 -219
- package/tsconfig.build.json +0 -6
package/README.md
CHANGED
|
@@ -11,11 +11,11 @@ A standardized way to format values in your React components.
|
|
|
11
11
|
</h3>
|
|
12
12
|
|
|
13
13
|
<p align="center">
|
|
14
|
-
Afformative helps UI component libraries
|
|
14
|
+
Afformative helps UI component libraries display arbitrary data in a reusable, plug-and-play fashion. Formatting dates and enum translations in your select fields and data grids has never been easier.
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
17
|
<p align="center">
|
|
18
|
-
<a href="https://github.com/wafflepie/
|
|
18
|
+
<a href="https://github.com/wafflepie/afformative/blob/master/LICENSE">
|
|
19
19
|
<img src="https://flat.badgen.net/badge/license/MIT/blue" alt="MIT License" />
|
|
20
20
|
</a>
|
|
21
21
|
|
|
@@ -26,94 +26,113 @@ Afformative helps UI component libraries visualise arbitrary data in a reusable,
|
|
|
26
26
|
|
|
27
27
|
## Installation
|
|
28
28
|
|
|
29
|
-
Use
|
|
29
|
+
Use one of these commands, depending on your preferred package manager:
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
32
|
yarn add afformative
|
|
33
33
|
|
|
34
|
+
pnpm add afformative
|
|
35
|
+
|
|
34
36
|
npm i afformative
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
## Quick Start
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
### The Holy Standard
|
|
41
|
+
A formatter is an object with `format`, `stringify`, and `compare` methods. Formatters must be created using the `createFormatter` function.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
`createFormatter` accepts a single object parameter. `format` is the only required property, but specifying `stringify` is recommended in most cases.
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
```tsx
|
|
46
|
+
import { createFormatter } from "afformative"
|
|
47
|
+
import { ReactNode } from "react"
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const dateFormatter = createFormatter<Date, ReactNode>({
|
|
50
|
+
format: value => <time dateTime={value.toISOString()}>{value.toLocaleDateString()}</time>,
|
|
51
|
+
stringify: value => value.toLocaleDateString(),
|
|
52
|
+
})
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
dateFormatter.format(new Date()) // <time dateTime="2026-05-30T09:17:26.263Z">30/05/2026</time>
|
|
55
|
+
dateFormatter.stringify(new Date()) // "30/05/2026"
|
|
53
56
|
```
|
|
54
57
|
|
|
55
|
-
Consume formatters in your UI component library
|
|
58
|
+
Consume formatters in your UI component library via a conventional `formatter` prop.
|
|
56
59
|
|
|
57
|
-
```
|
|
58
|
-
import {
|
|
60
|
+
```tsx
|
|
61
|
+
import { Formatter } from "afformative"
|
|
62
|
+
import { ReactNode } from "react"
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<select {...otherProps}>
|
|
65
|
-
{items.map(item => {
|
|
66
|
-
const text = formatter.format(item)
|
|
64
|
+
interface ListProps<TItem> {
|
|
65
|
+
formatter: Formatter<TItem, ReactNode>
|
|
66
|
+
items: TItem[]
|
|
67
|
+
}
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
</select>
|
|
69
|
+
const List = <TItem extends unknown>({ formatter, items }: ListProps<TItem>) => (
|
|
70
|
+
<ul>
|
|
71
|
+
{items.map(item => (
|
|
72
|
+
<li key={formatter.stringify(item)}>{formatter.format(item)}</li>
|
|
73
|
+
))}
|
|
74
|
+
</ul>
|
|
75
75
|
)
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Although formatters can render icons or custom translation components, we often need to access primitive data instead of React elements.
|
|
78
|
+
The `stringify` method is useful when you need a plain string representation of a value. For example, a combobox component can use it to match items against the user's typed input.
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
## Compare
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
Every formatter exposes a `compare` method, which can be used to sort values. The default implementation compares the return values of `stringify` via `localeCompare`. In the following example, `Amount` objects are sorted first by currency, then by value.
|
|
85
83
|
|
|
86
|
-
```
|
|
87
|
-
import {
|
|
84
|
+
```tsx
|
|
85
|
+
import { createFormatter } from "afformative"
|
|
86
|
+
import { ReactNode } from "react"
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
interface Amount {
|
|
89
|
+
currency: string
|
|
90
|
+
value: number
|
|
91
|
+
}
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
const amountFormatter = createFormatter<Amount, ReactNode>({
|
|
94
|
+
format: ({ currency, value }) => (
|
|
95
|
+
<span className="currency">{`${currency} ${value.toFixed(2)}`}</span>
|
|
96
|
+
),
|
|
97
|
+
stringify: ({ currency, value }) => `${currency} ${value.toFixed(2)}`,
|
|
98
|
+
compare: (a, b) => a.currency.localeCompare(b.currency) || a.value - b.value,
|
|
95
99
|
})
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
const amounts: Amount[] = [
|
|
102
|
+
{ currency: "USD", value: 3 },
|
|
103
|
+
{ currency: "EUR", value: 1 },
|
|
104
|
+
{ currency: "EUR", value: 5 },
|
|
105
|
+
{ currency: "USD", value: 2 },
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
amounts.sort(amountFormatter.compare)
|
|
109
|
+
// [{ EUR, 1 }, { EUR, 5 }, { USD, 2 }, { USD, 3 }]
|
|
99
110
|
```
|
|
100
111
|
|
|
101
|
-
|
|
112
|
+
## Usage Context
|
|
102
113
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
You can pass an optional usage context object to all formatter methods. Let's use a dummy table component as an example.
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
import { Formatter } from "afformative"
|
|
118
|
+
import { ReactNode } from "react"
|
|
107
119
|
|
|
108
|
-
|
|
120
|
+
interface TableFormatterUsageContext {
|
|
121
|
+
row: number[]
|
|
122
|
+
cellIndex: number
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface TableProps {
|
|
126
|
+
rows: number[][]
|
|
127
|
+
formatter: Formatter<number, ReactNode, TableFormatterUsageContext>
|
|
128
|
+
}
|
|
109
129
|
|
|
110
|
-
|
|
111
|
-
const Table = ({ rows, formatter = identityFormatter }) => (
|
|
130
|
+
const Table = ({ rows, formatter }: TableProps) => (
|
|
112
131
|
<table>
|
|
113
132
|
{rows.map(row => (
|
|
114
133
|
<tr>
|
|
115
134
|
{row.map((cell, cellIndex) => (
|
|
116
|
-
<td>{formatter.format(cell,
|
|
135
|
+
<td>{formatter.format(cell, { row, cellIndex })}</td>
|
|
117
136
|
))}
|
|
118
137
|
</tr>
|
|
119
138
|
))}
|
|
@@ -121,70 +140,50 @@ const Table = ({ rows, formatter = identityFormatter }) => (
|
|
|
121
140
|
)
|
|
122
141
|
```
|
|
123
142
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
```js
|
|
127
|
-
const rowTrendFormatter = makeFormatter((value, suggestions, { row, cellIndex }) => {
|
|
128
|
-
if (cellIndex === 0) {
|
|
129
|
-
return <span>{value}</span>
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const previousValue = row[cellIndex - 1]
|
|
133
|
-
|
|
134
|
-
return <span style={{ color: value >= previousValue ? "green" : "red" }}>{value}</span>
|
|
135
|
-
})
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Of course, this formatter only makes sense for our table component, nowhere else.
|
|
139
|
-
|
|
140
|
-
Because `row` and `cellIndex` are passed as the data context, the formatter still receives just the cell value as its first parameter! This allows us to pass other generic formatters (e.g. a currency formatter) to the table component without having to worry about the value structure.
|
|
143
|
+
Usage context allows the users of this table component to write purpose-built formatters, making it possible to take other values in the same row into account. For example, the following formatter would change the color of the cell value based on the previous value in the same row.
|
|
141
144
|
|
|
142
|
-
|
|
145
|
+
```tsx
|
|
146
|
+
import { createFormatter } from "afformative"
|
|
147
|
+
import { ReactNode } from "react"
|
|
143
148
|
|
|
144
|
-
|
|
149
|
+
import { TableFormatterUsageContext } from "./Table"
|
|
145
150
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const intl = useIntl()
|
|
151
|
+
const rowTrendFormatter = createFormatter<number, ReactNode, TableFormatterUsageContext>({
|
|
152
|
+
format: (value, { row, cellIndex }) => {
|
|
153
|
+
if (cellIndex === 0) {
|
|
154
|
+
return <span>{value}</span>
|
|
155
|
+
}
|
|
152
156
|
|
|
153
|
-
|
|
154
|
-
() =>
|
|
155
|
-
makeFormatter(value =>
|
|
156
|
-
intl.formatMessage({
|
|
157
|
-
defaultMessage: value,
|
|
158
|
-
id: enumTranslationKeys[value],
|
|
159
|
-
}),
|
|
160
|
-
),
|
|
161
|
-
[intl, enumTranslationKeys],
|
|
162
|
-
)
|
|
163
|
-
}
|
|
157
|
+
const previousValue = row[cellIndex - 1]
|
|
164
158
|
|
|
165
|
-
|
|
159
|
+
return <span style={{ color: value >= previousValue ? "green" : "red" }}>{value}</span>
|
|
160
|
+
},
|
|
161
|
+
})
|
|
166
162
|
```
|
|
167
163
|
|
|
168
|
-
|
|
164
|
+
This formatter only makes sense in the context of our table component.
|
|
165
|
+
|
|
166
|
+
Because `row` and `cellIndex` are passed as the usage context, the formatter still receives only the cell value as its first parameter. This means generic formatters (e.g. a currency formatter) can be passed to the table component without any changes.
|
|
169
167
|
|
|
170
|
-
|
|
168
|
+
## Accessing React Context
|
|
171
169
|
|
|
172
|
-
|
|
170
|
+
Create formatters inside custom hooks to access React context values such as translations or application state.
|
|
173
171
|
|
|
174
|
-
```
|
|
175
|
-
const
|
|
172
|
+
```tsx
|
|
173
|
+
const useEnumFormatter = (enumType: string): Formatter<string, ReactNode> => {
|
|
174
|
+
const enumTranslationKeys = useSelector(selectEnumTranslationKeys(enumType))
|
|
176
175
|
const intl = useIntl()
|
|
177
176
|
|
|
178
177
|
return useMemo(
|
|
179
178
|
() =>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
179
|
+
createFormatter<string, ReactNode>({
|
|
180
|
+
format: value => (
|
|
181
|
+
<FormattedMessage defaultMessage={value} id={enumTranslationKeys[value]} />
|
|
182
|
+
),
|
|
183
|
+
stringify: value =>
|
|
184
|
+
intl.formatMessage({ defaultMessage: value, id: enumTranslationKeys[value] }),
|
|
186
185
|
}),
|
|
187
|
-
[
|
|
186
|
+
[intl, enumTranslationKeys],
|
|
188
187
|
)
|
|
189
188
|
}
|
|
190
189
|
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/createFormatter.ts
|
|
3
|
+
const createFormatter = (param) => {
|
|
4
|
+
const { format: formatParam, stringify: stringifyParam, compare: compareParam, ...rest } = param;
|
|
5
|
+
const format = (value, usageContext) => formatParam(value, usageContext ?? {});
|
|
6
|
+
const stringify = stringifyParam ? (value, usageContext) => stringifyParam(value, usageContext ?? {}) : (value, usageContext) => String(format(value, usageContext ?? {}));
|
|
7
|
+
return {
|
|
8
|
+
compare: compareParam ? (a, b, usageContext) => compareParam(a, b, usageContext ?? {}) : (a, b, usageContext) => stringify(a, usageContext ?? {}).localeCompare(stringify(b, usageContext ?? {})),
|
|
9
|
+
format,
|
|
10
|
+
stringify,
|
|
11
|
+
...rest
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
exports.createFormatter = createFormatter;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/createFormatter.d.ts
|
|
2
|
+
interface FormatterFormatDefinition<TInput, TOutput, TUsageContext extends object = object> {
|
|
3
|
+
(value: TInput, usageContext: Partial<TUsageContext>): TOutput;
|
|
4
|
+
}
|
|
5
|
+
interface FormatterFormat<TInput, TOutput, TUsageContext extends object = object> {
|
|
6
|
+
(value: TInput, usageContext?: Partial<TUsageContext>): TOutput;
|
|
7
|
+
}
|
|
8
|
+
interface FormatterStringifyDefinition<TInput, TUsageContext extends object = object> {
|
|
9
|
+
(value: TInput, usageContext: Partial<TUsageContext>): string;
|
|
10
|
+
}
|
|
11
|
+
interface FormatterStringify<TInput, TUsageContext extends object = object> {
|
|
12
|
+
(value: TInput, usageContext?: Partial<TUsageContext>): string;
|
|
13
|
+
}
|
|
14
|
+
interface FormatterCompareDefinition<TInput, TUsageContext extends object = object> {
|
|
15
|
+
(a: TInput, b: TInput, usageContext: Partial<TUsageContext>): number;
|
|
16
|
+
}
|
|
17
|
+
interface FormatterCompare<TInput, TUsageContext extends object = object> {
|
|
18
|
+
(a: TInput, b: TInput, usageContext?: Partial<TUsageContext>): number;
|
|
19
|
+
}
|
|
20
|
+
interface Formatter<TInput, TOutput, TUsageContext extends object = object> {
|
|
21
|
+
compare: FormatterCompare<TInput, TUsageContext>;
|
|
22
|
+
format: FormatterFormat<TInput, TOutput, TUsageContext>;
|
|
23
|
+
stringify: FormatterStringify<TInput, TUsageContext>;
|
|
24
|
+
name?: string;
|
|
25
|
+
}
|
|
26
|
+
interface CreateFormatterParam<TInput, TOutput, TUsageContext extends object = object> {
|
|
27
|
+
compare?: FormatterCompareDefinition<TInput, TUsageContext>;
|
|
28
|
+
format: FormatterFormatDefinition<TInput, TOutput, TUsageContext>;
|
|
29
|
+
stringify?: FormatterStringifyDefinition<TInput, TUsageContext>;
|
|
30
|
+
}
|
|
31
|
+
declare const createFormatter: <TInput, TOutput, TUsageContext extends object = object>(param: CreateFormatterParam<TInput, TOutput, TUsageContext>) => Formatter<TInput, TOutput, TUsageContext>;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { CreateFormatterParam, Formatter, FormatterCompare, FormatterCompareDefinition, FormatterFormat, FormatterFormatDefinition, FormatterStringify, FormatterStringifyDefinition, createFormatter };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/createFormatter.d.ts
|
|
2
|
+
interface FormatterFormatDefinition<TInput, TOutput, TUsageContext extends object = object> {
|
|
3
|
+
(value: TInput, usageContext: Partial<TUsageContext>): TOutput;
|
|
4
|
+
}
|
|
5
|
+
interface FormatterFormat<TInput, TOutput, TUsageContext extends object = object> {
|
|
6
|
+
(value: TInput, usageContext?: Partial<TUsageContext>): TOutput;
|
|
7
|
+
}
|
|
8
|
+
interface FormatterStringifyDefinition<TInput, TUsageContext extends object = object> {
|
|
9
|
+
(value: TInput, usageContext: Partial<TUsageContext>): string;
|
|
10
|
+
}
|
|
11
|
+
interface FormatterStringify<TInput, TUsageContext extends object = object> {
|
|
12
|
+
(value: TInput, usageContext?: Partial<TUsageContext>): string;
|
|
13
|
+
}
|
|
14
|
+
interface FormatterCompareDefinition<TInput, TUsageContext extends object = object> {
|
|
15
|
+
(a: TInput, b: TInput, usageContext: Partial<TUsageContext>): number;
|
|
16
|
+
}
|
|
17
|
+
interface FormatterCompare<TInput, TUsageContext extends object = object> {
|
|
18
|
+
(a: TInput, b: TInput, usageContext?: Partial<TUsageContext>): number;
|
|
19
|
+
}
|
|
20
|
+
interface Formatter<TInput, TOutput, TUsageContext extends object = object> {
|
|
21
|
+
compare: FormatterCompare<TInput, TUsageContext>;
|
|
22
|
+
format: FormatterFormat<TInput, TOutput, TUsageContext>;
|
|
23
|
+
stringify: FormatterStringify<TInput, TUsageContext>;
|
|
24
|
+
name?: string;
|
|
25
|
+
}
|
|
26
|
+
interface CreateFormatterParam<TInput, TOutput, TUsageContext extends object = object> {
|
|
27
|
+
compare?: FormatterCompareDefinition<TInput, TUsageContext>;
|
|
28
|
+
format: FormatterFormatDefinition<TInput, TOutput, TUsageContext>;
|
|
29
|
+
stringify?: FormatterStringifyDefinition<TInput, TUsageContext>;
|
|
30
|
+
}
|
|
31
|
+
declare const createFormatter: <TInput, TOutput, TUsageContext extends object = object>(param: CreateFormatterParam<TInput, TOutput, TUsageContext>) => Formatter<TInput, TOutput, TUsageContext>;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { CreateFormatterParam, Formatter, FormatterCompare, FormatterCompareDefinition, FormatterFormat, FormatterFormatDefinition, FormatterStringify, FormatterStringifyDefinition, createFormatter };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/createFormatter.ts
|
|
2
|
+
const createFormatter = (param) => {
|
|
3
|
+
const { format: formatParam, stringify: stringifyParam, compare: compareParam, ...rest } = param;
|
|
4
|
+
const format = (value, usageContext) => formatParam(value, usageContext ?? {});
|
|
5
|
+
const stringify = stringifyParam ? (value, usageContext) => stringifyParam(value, usageContext ?? {}) : (value, usageContext) => String(format(value, usageContext ?? {}));
|
|
6
|
+
return {
|
|
7
|
+
compare: compareParam ? (a, b, usageContext) => compareParam(a, b, usageContext ?? {}) : (a, b, usageContext) => stringify(a, usageContext ?? {}).localeCompare(stringify(b, usageContext ?? {})),
|
|
8
|
+
format,
|
|
9
|
+
stringify,
|
|
10
|
+
...rest
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { createFormatter };
|
package/package.json
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "afformative",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"license": "MIT",
|
|
5
|
-
"main": "dist/afformative.cjs.js",
|
|
6
|
-
"module": "dist/afformative.esm.js",
|
|
7
|
-
"unpkg": "dist/afformative.umd.js",
|
|
8
|
-
"types": "dist/types/index.d.ts",
|
|
3
|
+
"version": "0.7.0-beta.2",
|
|
9
4
|
"description": "A standardized way to format values in your React components.",
|
|
10
5
|
"keywords": [
|
|
11
6
|
"react",
|
|
@@ -24,15 +19,49 @@
|
|
|
24
19
|
"values"
|
|
25
20
|
],
|
|
26
21
|
"repository": "https://github.com/wafflepie/afformative",
|
|
22
|
+
"license": "MIT",
|
|
27
23
|
"contributors": [
|
|
28
|
-
"Vaclav Jancarik <
|
|
24
|
+
"Vaclav Jancarik <hi@wafflepie.dev>"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"type": "module",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"require": "./dist/index.cjs"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"main": "./dist/index.cjs",
|
|
36
|
+
"module": "./dist/index.mjs",
|
|
37
|
+
"types": "./dist/index.d.cts",
|
|
38
|
+
"files": [
|
|
39
|
+
"dist"
|
|
29
40
|
],
|
|
30
|
-
"
|
|
31
|
-
"
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsdown",
|
|
43
|
+
"prepublishOnly": "pnpm run build",
|
|
44
|
+
"release": "bumpp",
|
|
45
|
+
"test": "pnpm test:prettier && pnpm run test:typescript && pnpm run test:eslint && pnpm run test:vitest",
|
|
46
|
+
"test:eslint": "eslint src",
|
|
47
|
+
"test:prettier": "prettier --check src",
|
|
48
|
+
"test:typescript": "tsc --noEmit",
|
|
49
|
+
"test:vitest": "vitest run"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@eslint/js": "^10.0.1",
|
|
53
|
+
"@types/node": "^25.6.2",
|
|
54
|
+
"@typescript/native-preview": "^7.0.0-dev.20260527.2",
|
|
55
|
+
"bumpp": "^11.1.0",
|
|
56
|
+
"eslint": "^10.4.1",
|
|
57
|
+
"prettier": "^3.8.3",
|
|
58
|
+
"tsdown": "^0.22.1",
|
|
59
|
+
"typescript": "^6.0.3",
|
|
60
|
+
"typescript-eslint": "^8.60.0",
|
|
61
|
+
"vitest": "^4.1.7"
|
|
32
62
|
},
|
|
63
|
+
"packageManager": "pnpm@11.5.0+sha512.dbfcc4f81cf48597afd4bc391ffdf12c11f1a9fb83a395bfa6b0a2d9cc2fd8ffebafdb1ccbd529632153f793904c2615b7f09fe1a345473fd1c35845172a8eb1",
|
|
33
64
|
"publishConfig": {
|
|
34
65
|
"access": "public"
|
|
35
|
-
}
|
|
36
|
-
"sideEffects": false,
|
|
37
|
-
"gitHead": "ddc8c8682e2777c730108466792b7670d8a43f06"
|
|
66
|
+
}
|
|
38
67
|
}
|
package/dist/afformative.cjs.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
|
|
6
|
-
|
|
7
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
|
-
|
|
9
|
-
var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray);
|
|
10
|
-
|
|
11
|
-
var ensureFormatSuggestionIntegrity = function ensureFormatSuggestionIntegrity(suggestions) {
|
|
12
|
-
return suggestions.includes("primitive") || !suggestions.includes("comparable") ? suggestions : ["primitive"].concat(_toConsumableArray__default["default"](suggestions));
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
var ensureFormatAsPrimitiveSuggestionIntegrity = function ensureFormatAsPrimitiveSuggestionIntegrity(suggestions) {
|
|
16
|
-
return suggestions.includes("primitive") ? suggestions : ["primitive"].concat(_toConsumableArray__default["default"](suggestions));
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Creates a new formatter.
|
|
21
|
-
*
|
|
22
|
-
* @param format Function used to format the value.
|
|
23
|
-
* @param formatterOptions Additional options for the formatter.
|
|
24
|
-
*/
|
|
25
|
-
var makeFormatter = function makeFormatter(format, formatterOptions) {
|
|
26
|
-
var formatter = function formatter(props) {
|
|
27
|
-
var _format, _props$suggestions;
|
|
28
|
-
|
|
29
|
-
return (_format = format(props.children, (_props$suggestions = props.suggestions) !== null && _props$suggestions !== void 0 ? _props$suggestions : [], props)) !== null && _format !== void 0 ? _format : null;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
formatter.displayName = formatterOptions === null || formatterOptions === void 0 ? void 0 : formatterOptions.displayName;
|
|
33
|
-
|
|
34
|
-
formatter.format = function (value) {
|
|
35
|
-
var suggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
36
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
37
|
-
return format(value, ensureFormatSuggestionIntegrity(suggestions), dataContext);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
formatter.formatAsPrimitive = function (value) {
|
|
41
|
-
var suggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
42
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
43
|
-
return format(value, ensureFormatAsPrimitiveSuggestionIntegrity(suggestions), dataContext);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
formatter.wrap = function (nextFormat, nextFormatterOptions) {
|
|
47
|
-
var nextFormatter = makeFormatter(function (value, suggestions, dataContext) {
|
|
48
|
-
var delegate = function delegate(delegatedValue, delegatedSuggestions, delegatedDataContext) {
|
|
49
|
-
return formatter.format(delegatedValue, delegatedSuggestions !== null && delegatedSuggestions !== void 0 ? delegatedSuggestions : suggestions, delegatedDataContext !== null && delegatedDataContext !== void 0 ? delegatedDataContext : dataContext);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
return nextFormat(delegate, value, suggestions, dataContext);
|
|
53
|
-
}, nextFormatterOptions !== null && nextFormatterOptions !== void 0 ? nextFormatterOptions : formatterOptions);
|
|
54
|
-
nextFormatter.innerFormatter = formatter;
|
|
55
|
-
return nextFormatter;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
return formatter;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
exports.makeFormatter = makeFormatter;
|
package/dist/afformative.esm.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import _toConsumableArray from '@babel/runtime/helpers/esm/toConsumableArray';
|
|
2
|
-
|
|
3
|
-
var ensureFormatSuggestionIntegrity = function ensureFormatSuggestionIntegrity(suggestions) {
|
|
4
|
-
return suggestions.includes("primitive") || !suggestions.includes("comparable") ? suggestions : ["primitive"].concat(_toConsumableArray(suggestions));
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
var ensureFormatAsPrimitiveSuggestionIntegrity = function ensureFormatAsPrimitiveSuggestionIntegrity(suggestions) {
|
|
8
|
-
return suggestions.includes("primitive") ? suggestions : ["primitive"].concat(_toConsumableArray(suggestions));
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Creates a new formatter.
|
|
13
|
-
*
|
|
14
|
-
* @param format Function used to format the value.
|
|
15
|
-
* @param formatterOptions Additional options for the formatter.
|
|
16
|
-
*/
|
|
17
|
-
var makeFormatter = function makeFormatter(format, formatterOptions) {
|
|
18
|
-
var formatter = function formatter(props) {
|
|
19
|
-
var _format, _props$suggestions;
|
|
20
|
-
|
|
21
|
-
return (_format = format(props.children, (_props$suggestions = props.suggestions) !== null && _props$suggestions !== void 0 ? _props$suggestions : [], props)) !== null && _format !== void 0 ? _format : null;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
formatter.displayName = formatterOptions === null || formatterOptions === void 0 ? void 0 : formatterOptions.displayName;
|
|
25
|
-
|
|
26
|
-
formatter.format = function (value) {
|
|
27
|
-
var suggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
28
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
29
|
-
return format(value, ensureFormatSuggestionIntegrity(suggestions), dataContext);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
formatter.formatAsPrimitive = function (value) {
|
|
33
|
-
var suggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
34
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
35
|
-
return format(value, ensureFormatAsPrimitiveSuggestionIntegrity(suggestions), dataContext);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
formatter.wrap = function (nextFormat, nextFormatterOptions) {
|
|
39
|
-
var nextFormatter = makeFormatter(function (value, suggestions, dataContext) {
|
|
40
|
-
var delegate = function delegate(delegatedValue, delegatedSuggestions, delegatedDataContext) {
|
|
41
|
-
return formatter.format(delegatedValue, delegatedSuggestions !== null && delegatedSuggestions !== void 0 ? delegatedSuggestions : suggestions, delegatedDataContext !== null && delegatedDataContext !== void 0 ? delegatedDataContext : dataContext);
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
return nextFormat(delegate, value, suggestions, dataContext);
|
|
45
|
-
}, nextFormatterOptions !== null && nextFormatterOptions !== void 0 ? nextFormatterOptions : formatterOptions);
|
|
46
|
-
nextFormatter.innerFormatter = formatter;
|
|
47
|
-
return nextFormatter;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
return formatter;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export { makeFormatter };
|
package/dist/afformative.umd.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Afformative = {}));
|
|
5
|
-
})(this, (function (exports) { 'use strict';
|
|
6
|
-
|
|
7
|
-
function _arrayLikeToArray(arr, len) {
|
|
8
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
9
|
-
|
|
10
|
-
for (var i = 0, arr2 = new Array(len); i < len; i++) {
|
|
11
|
-
arr2[i] = arr[i];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return arr2;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function _arrayWithoutHoles(arr) {
|
|
18
|
-
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function _iterableToArray(iter) {
|
|
22
|
-
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function _unsupportedIterableToArray(o, minLen) {
|
|
26
|
-
if (!o) return;
|
|
27
|
-
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
|
28
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
29
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
30
|
-
if (n === "Map" || n === "Set") return Array.from(o);
|
|
31
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function _nonIterableSpread() {
|
|
35
|
-
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function _toConsumableArray(arr) {
|
|
39
|
-
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
var ensureFormatSuggestionIntegrity = function ensureFormatSuggestionIntegrity(suggestions) {
|
|
43
|
-
return suggestions.includes("primitive") || !suggestions.includes("comparable") ? suggestions : ["primitive"].concat(_toConsumableArray(suggestions));
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
var ensureFormatAsPrimitiveSuggestionIntegrity = function ensureFormatAsPrimitiveSuggestionIntegrity(suggestions) {
|
|
47
|
-
return suggestions.includes("primitive") ? suggestions : ["primitive"].concat(_toConsumableArray(suggestions));
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Creates a new formatter.
|
|
52
|
-
*
|
|
53
|
-
* @param format Function used to format the value.
|
|
54
|
-
* @param formatterOptions Additional options for the formatter.
|
|
55
|
-
*/
|
|
56
|
-
var makeFormatter = function makeFormatter(format, formatterOptions) {
|
|
57
|
-
var formatter = function formatter(props) {
|
|
58
|
-
var _format, _props$suggestions;
|
|
59
|
-
|
|
60
|
-
return (_format = format(props.children, (_props$suggestions = props.suggestions) !== null && _props$suggestions !== void 0 ? _props$suggestions : [], props)) !== null && _format !== void 0 ? _format : null;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
formatter.displayName = formatterOptions === null || formatterOptions === void 0 ? void 0 : formatterOptions.displayName;
|
|
64
|
-
|
|
65
|
-
formatter.format = function (value) {
|
|
66
|
-
var suggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
67
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
68
|
-
return format(value, ensureFormatSuggestionIntegrity(suggestions), dataContext);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
formatter.formatAsPrimitive = function (value) {
|
|
72
|
-
var suggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
73
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
74
|
-
return format(value, ensureFormatAsPrimitiveSuggestionIntegrity(suggestions), dataContext);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
formatter.wrap = function (nextFormat, nextFormatterOptions) {
|
|
78
|
-
var nextFormatter = makeFormatter(function (value, suggestions, dataContext) {
|
|
79
|
-
var delegate = function delegate(delegatedValue, delegatedSuggestions, delegatedDataContext) {
|
|
80
|
-
return formatter.format(delegatedValue, delegatedSuggestions !== null && delegatedSuggestions !== void 0 ? delegatedSuggestions : suggestions, delegatedDataContext !== null && delegatedDataContext !== void 0 ? delegatedDataContext : dataContext);
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
return nextFormat(delegate, value, suggestions, dataContext);
|
|
84
|
-
}, nextFormatterOptions !== null && nextFormatterOptions !== void 0 ? nextFormatterOptions : formatterOptions);
|
|
85
|
-
nextFormatter.innerFormatter = formatter;
|
|
86
|
-
return nextFormatter;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
return formatter;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
exports.makeFormatter = makeFormatter;
|
|
93
|
-
|
|
94
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
95
|
-
|
|
96
|
-
}));
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).Afformative={})}(this,(function(t){"use strict";function n(t,n){(null==n||n>t.length)&&(n=t.length);for(var r=0,e=Array(n);n>r;r++)e[r]=t[r];return e}function r(t){return function(t){if(Array.isArray(t))return n(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,r){if(t){if("string"==typeof t)return n(t,r);var e=Object.prototype.toString.call(t).slice(8,-1);return"Object"===e&&t.constructor&&(e=t.constructor.name),"Map"===e||"Set"===e?Array.from(t):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?n(t,r):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}var e=function(t){return t.includes("primitive")||!t.includes("comparable")?t:["primitive"].concat(r(t))},i=function(t){return t.includes("primitive")?t:["primitive"].concat(r(t))};t.makeFormatter=function t(n,r){var o=function(t){var r,e;return null!==(r=n(t.children,null!==(e=t.suggestions)&&void 0!==e?e:[],t))&&void 0!==r?r:null};return o.displayName=null==r?void 0:r.displayName,o.format=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return n(t,e(r),i)},o.formatAsPrimitive=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return n(t,i(r),e)},o.wrap=function(n,e){var i=t((function(t,r,e){return n((function(t,n,i){return o.format(t,null!=n?n:r,null!=i?i:e)}),t,r,e)}),null!=e?e:r);return i.innerFormatter=o,i},o},Object.defineProperty(t,"__esModule",{value:!0})}));
|
package/dist/types/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA"}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
declare type PrimitiveSuggestion = "primitive" | "comparable";
|
|
2
|
-
declare type Suggestion = PrimitiveSuggestion | "abbreviated" | "as-icon"
|
|
3
|
-
/**
|
|
4
|
-
* @deprecated Since v0.6.3. Use `"as-icon"` or `"with-icon"` instead.
|
|
5
|
-
*/
|
|
6
|
-
| "icon" | "verbose" | "with-icon";
|
|
7
|
-
declare type DataContext = Record<string, any>;
|
|
8
|
-
interface FormatterOptions {
|
|
9
|
-
/** Formatter name, useful for debugging or advanced pattern matching. */
|
|
10
|
-
displayName?: string;
|
|
11
|
-
}
|
|
12
|
-
interface FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
13
|
-
(
|
|
14
|
-
/** Value to format. */
|
|
15
|
-
value: TInput,
|
|
16
|
-
/** Suggestions passed by the consumer of a formatter. */
|
|
17
|
-
suggestions: Suggestion[],
|
|
18
|
-
/** Additional data context to be used by the formatter. */
|
|
19
|
-
dataContext: Partial<TDataContext>): TOutput | TPrimitiveOutput;
|
|
20
|
-
}
|
|
21
|
-
interface FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
22
|
-
(
|
|
23
|
-
/** Value to format. */
|
|
24
|
-
value: TInput,
|
|
25
|
-
/** Suggestions the formatter should take note of. */
|
|
26
|
-
suggestions?: Suggestion[],
|
|
27
|
-
/** Additional data context the formatter might find useful. */
|
|
28
|
-
dataContext?: Partial<TDataContext>): TOutput | TPrimitiveOutput;
|
|
29
|
-
}
|
|
30
|
-
interface FormatAsPrimitiveMethod<TInput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
31
|
-
(
|
|
32
|
-
/** Value to format. */
|
|
33
|
-
value: TInput,
|
|
34
|
-
/** Suggestions the formatter should take note of in addition to `primitive`. */
|
|
35
|
-
suggestions?: Suggestion[],
|
|
36
|
-
/** Additional data context the formatter might find useful. */
|
|
37
|
-
dataContext?: Partial<TDataContext>): TPrimitiveOutput;
|
|
38
|
-
}
|
|
39
|
-
interface FormatChainDefinition<TInnerInput, TInnerOutput, TInnerPrimitiveInput, TInnerDataContext extends DataContext, TOuterInput, TOuterOutput, TOuterPrimitiveOutput, TOuterDataContext extends DataContext> {
|
|
40
|
-
(
|
|
41
|
-
/**
|
|
42
|
-
* The `formatter.format` method which can be used to delegate the formatting
|
|
43
|
-
* to the wrapped formatter. Delegation is simplified so if no suggestions or contextual
|
|
44
|
-
* props are passed, the original ones are used instead.
|
|
45
|
-
*/
|
|
46
|
-
delegate: FormatMethod<TInnerInput, TInnerOutput, TInnerPrimitiveInput, TInnerDataContext>,
|
|
47
|
-
/** Value to format. */
|
|
48
|
-
value: TOuterInput,
|
|
49
|
-
/** Suggestions the formatter should take note of. */
|
|
50
|
-
suggestions: Suggestion[],
|
|
51
|
-
/** Additional data context the formatter might find useful. */
|
|
52
|
-
dataContext: Partial<TOuterDataContext>): TOuterOutput | TOuterPrimitiveOutput;
|
|
53
|
-
}
|
|
54
|
-
declare type FormatterProps<TInput, TDataContext extends DataContext> = {
|
|
55
|
-
/** Value to format. */
|
|
56
|
-
children: TInput;
|
|
57
|
-
/** Suggestions the formatter should take note of. */
|
|
58
|
-
suggestions?: Suggestion[];
|
|
59
|
-
} & Partial<TDataContext>;
|
|
60
|
-
export interface Formatter<TInput, TOutput, TPrimitiveOutput = TOutput, TDataContext extends DataContext = DataContext> {
|
|
61
|
-
/** Formatter name, useful for debugging or advanced pattern matching. */
|
|
62
|
-
displayName?: string;
|
|
63
|
-
/** Formats a value. */
|
|
64
|
-
format: FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext>;
|
|
65
|
-
/** Formats a value with the `primitive` suggestion. */
|
|
66
|
-
formatAsPrimitive: FormatAsPrimitiveMethod<TInput, TPrimitiveOutput, TDataContext>;
|
|
67
|
-
/** The callee of the `wrap` method used to produce this formatter. */
|
|
68
|
-
innerFormatter?: Formatter<any, any, any, any>;
|
|
69
|
-
/**
|
|
70
|
-
* Creates a new formatter from an existing one. Allows overriding of formatter behaviour
|
|
71
|
-
* for certain values.
|
|
72
|
-
*/
|
|
73
|
-
wrap: <TNextInput = TInput, TNextOutput = TOutput, TNextPrimitiveOutput = TPrimitiveOutput, TNextDataContext extends TDataContext = TDataContext>(
|
|
74
|
-
/**
|
|
75
|
-
* Function used to format the value. Has the same signature as the one passed
|
|
76
|
-
* to `makeFormatter`, except a `delegate` function is passed in the first position.
|
|
77
|
-
* This function can be used to delegate formatting to the original (inner) formatter.
|
|
78
|
-
*/
|
|
79
|
-
nextFormat: FormatChainDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext, TNextInput, TNextOutput, TNextPrimitiveOutput, TNextDataContext>,
|
|
80
|
-
/** New formatter options, replacing the original ones. */
|
|
81
|
-
nextFormatterOptions?: FormatterOptions) => Formatter<TNextInput, TNextOutput, TNextPrimitiveOutput, TNextDataContext>;
|
|
82
|
-
/**
|
|
83
|
-
* Backwards-compatible way to use the formatter as a React component.
|
|
84
|
-
*
|
|
85
|
-
* @deprecated Since v0.6.0. Prefer using the `format` method instead.
|
|
86
|
-
*/
|
|
87
|
-
(props: FormatterProps<TInput, TDataContext>): TOutput | TPrimitiveOutput | null;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Creates a new formatter.
|
|
91
|
-
*
|
|
92
|
-
* @param format Function used to format the value.
|
|
93
|
-
* @param formatterOptions Additional options for the formatter.
|
|
94
|
-
*/
|
|
95
|
-
export declare const makeFormatter: <TInput, TOutput, TPrimitiveOutput = TOutput, TDataContext extends DataContext = DataContext>(format: FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext>, formatterOptions?: FormatterOptions | undefined) => Formatter<TInput, TOutput, TPrimitiveOutput, TDataContext>;
|
|
96
|
-
export {};
|
|
97
|
-
//# sourceMappingURL=makeFormatter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"makeFormatter.d.ts","sourceRoot":"","sources":["../../src/makeFormatter.ts"],"names":[],"mappings":"AAAA,aAAK,mBAAmB,GAAG,WAAW,GAAG,YAAY,CAAA;AAErD,aAAK,UAAU,GACX,mBAAmB,GACnB,aAAa,GACb,SAAS;AACX;;GAEG;GACD,MAAM,GACN,SAAS,GACT,WAAW,CAAA;AAUf,aAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAEtC,UAAU,gBAAgB;IACxB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,UAAU,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,YAAY,SAAS,WAAW;IAC5F;IACE,uBAAuB;IACvB,KAAK,EAAE,MAAM;IACb,yDAAyD;IACzD,WAAW,EAAE,UAAU,EAAE;IACzB,2DAA2D;IAC3D,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,GACjC,OAAO,GAAG,gBAAgB,CAAA;CAC9B;AAED,UAAU,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,YAAY,SAAS,WAAW;IACxF;IACE,uBAAuB;IACvB,KAAK,EAAE,MAAM;IACb,qDAAqD;IACrD,WAAW,CAAC,EAAE,UAAU,EAAE;IAC1B,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAClC,OAAO,GAAG,gBAAgB,CAAA;CAC9B;AAED,UAAU,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,EAAE,YAAY,SAAS,WAAW;IAC1F;IACE,uBAAuB;IACvB,KAAK,EAAE,MAAM;IACb,gFAAgF;IAChF,WAAW,CAAC,EAAE,UAAU,EAAE;IAC1B,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAClC,gBAAgB,CAAA;CACpB;AAED,UAAU,qBAAqB,CAC7B,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,SAAS,WAAW,EACrC,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,SAAS,WAAW;IAErC;IACE;;;;OAIG;IACH,QAAQ,EAAE,YAAY,CAAC,WAAW,EAAE,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,CAAC;IAC1F,uBAAuB;IACvB,KAAK,EAAE,WAAW;IAClB,qDAAqD;IACrD,WAAW,EAAE,UAAU,EAAE;IACzB,+DAA+D;IAC/D,WAAW,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACtC,YAAY,GAAG,qBAAqB,CAAA;CACxC;AAED,aAAK,cAAc,CAAC,MAAM,EAAE,YAAY,SAAS,WAAW,IAAI;IAC9D,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,qDAAqD;IACrD,WAAW,CAAC,EAAE,UAAU,EAAE,CAAA;CAC3B,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;AAEzB,MAAM,WAAW,SAAS,CACxB,MAAM,EACN,OAAO,EACP,gBAAgB,GAAG,OAAO,EAC1B,YAAY,SAAS,WAAW,GAAG,WAAW;IAE9C,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uBAAuB;IACvB,MAAM,EAAE,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAA;IACrE,uDAAuD;IACvD,iBAAiB,EAAE,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAA;IAClF,sEAAsE;IACtE,cAAc,CAAC,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;IAC9C;;;OAGG;IACH,IAAI,EAAE,CACJ,UAAU,GAAG,MAAM,EACnB,WAAW,GAAG,OAAO,EACrB,oBAAoB,GAAG,gBAAgB,EACvC,gBAAgB,SAAS,YAAY,GAAG,YAAY;IAEpD;;;;OAIG;IACH,UAAU,EAAE,qBAAqB,CAC/B,MAAM,EACN,OAAO,EACP,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,gBAAgB,CACjB;IACD,0DAA0D;IAC1D,oBAAoB,CAAC,EAAE,gBAAgB,KACpC,SAAS,CAAC,UAAU,EAAE,WAAW,EAAE,oBAAoB,EAAE,gBAAgB,CAAC,CAAA;IAC/E;;;;OAIG;IACH,CAAC,KAAK,EAAE,cAAc,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAAA;CACjF;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,yRAoEzB,CAAA"}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./makeFormatter"
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import { makeFormatter } from "./makeFormatter"
|
|
2
|
-
|
|
3
|
-
const toUpperCase = (string: string) => string.toUpperCase()
|
|
4
|
-
|
|
5
|
-
const upperCaseFormatter = makeFormatter<string, string>(toUpperCase)
|
|
6
|
-
|
|
7
|
-
interface ValueRecord {
|
|
8
|
-
value: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const valueRecordUpperCaseFormatter = makeFormatter<ValueRecord, ValueRecord, string>(
|
|
12
|
-
({ value }, suggestions) => {
|
|
13
|
-
if (suggestions.includes("primitive")) {
|
|
14
|
-
return toUpperCase(value)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return { value: toUpperCase(value) }
|
|
18
|
-
},
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
describe("makeFormatter", () => {
|
|
22
|
-
const format = jest.fn()
|
|
23
|
-
|
|
24
|
-
afterEach(() => {
|
|
25
|
-
jest.clearAllMocks()
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
describe("displayName", () => {
|
|
29
|
-
it("accepts a `displayName` option", () => {
|
|
30
|
-
const displayName = "upperCaseFormatter"
|
|
31
|
-
const formatter = makeFormatter<string, string>(toUpperCase, { displayName })
|
|
32
|
-
expect(formatter.displayName).toBe(displayName)
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
describe("format", () => {
|
|
37
|
-
it("handles trivial formatting", () => {
|
|
38
|
-
expect(upperCaseFormatter.format("foo")).toBe("FOO")
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it("passes through non-empty suggestions", () => {
|
|
42
|
-
const formatter = makeFormatter<string, string>(format)
|
|
43
|
-
formatter.format("foo", ["abbreviated"])
|
|
44
|
-
expect(format.mock.calls[0][1]).toEqual(["abbreviated"])
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it("passes through empty suggestions", () => {
|
|
48
|
-
const formatter = makeFormatter<string, string>(format)
|
|
49
|
-
formatter.format("foo", [])
|
|
50
|
-
expect(format.mock.calls[0][1]).toEqual([])
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it("defaults suggestions to an empty array", () => {
|
|
54
|
-
const formatter = makeFormatter<string, string>(format)
|
|
55
|
-
formatter.format("foo")
|
|
56
|
-
expect(format.mock.calls[0][1]).toEqual([])
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it("passes through the `primitive` suggestion", () => {
|
|
60
|
-
const formatter = makeFormatter<string, string>(format)
|
|
61
|
-
formatter.format("foo", ["primitive"])
|
|
62
|
-
expect(format.mock.calls[0][1]).toEqual(["primitive"])
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it("passes the `primitive` suggestion alongside `comparable` when missing", () => {
|
|
66
|
-
const formatter = makeFormatter<string, string>(format)
|
|
67
|
-
formatter.format("foo", ["comparable"])
|
|
68
|
-
expect(format.mock.calls[0][1]).toEqual(["primitive", "comparable"])
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it("does not pass the `primitive` suggestion alongside other suggestions when missing", () => {
|
|
72
|
-
const formatter = makeFormatter<string, string>(format)
|
|
73
|
-
formatter.format("foo", ["abbreviated", "verbose"])
|
|
74
|
-
expect(format.mock.calls[0][1]).toEqual(["abbreviated", "verbose"])
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it("supports data context", () => {
|
|
78
|
-
const formatter = makeFormatter<string, string>(format)
|
|
79
|
-
formatter.format("foo", [], { foo: "bar" })
|
|
80
|
-
expect(format.mock.calls[0][2]).toEqual({ foo: "bar" })
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it("defaults data context to an empty object", () => {
|
|
84
|
-
const formatter = makeFormatter<string, string>(format)
|
|
85
|
-
formatter.format("foo")
|
|
86
|
-
expect(format.mock.calls[0][2]).toEqual({})
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
describe("formatAsPrimitive", () => {
|
|
91
|
-
it("handles trivial formatting", () => {
|
|
92
|
-
expect(upperCaseFormatter.formatAsPrimitive("foo")).toBe("FOO")
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it("passes the `primitive` suggestion when no suggestions are passed", () => {
|
|
96
|
-
const formatter = makeFormatter<string, string>(format)
|
|
97
|
-
formatter.formatAsPrimitive("foo")
|
|
98
|
-
expect(format.mock.calls[0][1]).toEqual(["primitive"])
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it("passes the `primitive` suggestion when empty suggestions are passed", () => {
|
|
102
|
-
const formatter = makeFormatter<string, string>(format)
|
|
103
|
-
formatter.formatAsPrimitive("foo", [])
|
|
104
|
-
expect(format.mock.calls[0][1]).toEqual(["primitive"])
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it("passes the `primitive` suggestion when a different suggestion is passed", () => {
|
|
108
|
-
const formatter = makeFormatter<string, string>(format)
|
|
109
|
-
formatter.formatAsPrimitive("foo", ["abbreviated"])
|
|
110
|
-
expect(format.mock.calls[0][1]).toEqual(["primitive", "abbreviated"])
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it("passes through the `primitive` suggestion", () => {
|
|
114
|
-
const formatter = makeFormatter<string, string>(format)
|
|
115
|
-
formatter.formatAsPrimitive("foo", ["primitive"])
|
|
116
|
-
expect(format.mock.calls[0][1]).toEqual(["primitive"])
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it("passes the `primitive` suggestion alongside `comparable`", () => {
|
|
120
|
-
const formatter = makeFormatter<string, string>(format)
|
|
121
|
-
formatter.formatAsPrimitive("foo", ["comparable"])
|
|
122
|
-
expect(format.mock.calls[0][1]).toEqual(["primitive", "comparable"])
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
it("supports data context", () => {
|
|
126
|
-
const formatter = makeFormatter<string, string>(format)
|
|
127
|
-
formatter.formatAsPrimitive("foo", [], { foo: "bar" })
|
|
128
|
-
expect(format.mock.calls[0][2]).toEqual({ foo: "bar" })
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it("defaults data context to an empty object", () => {
|
|
132
|
-
const formatter = makeFormatter<string, string>(format)
|
|
133
|
-
formatter.formatAsPrimitive("foo")
|
|
134
|
-
expect(format.mock.calls[0][2]).toEqual({})
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
describe("wrap", () => {
|
|
139
|
-
it("handles trivial wrapping", () => {
|
|
140
|
-
const formatter = makeFormatter<string, string>(format).wrap(() => "bar")
|
|
141
|
-
expect(formatter.format("foo")).toBe("bar")
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it("handles single-value mapping", () => {
|
|
145
|
-
const formatter = makeFormatter<string, string>(format).wrap((delegate, value) =>
|
|
146
|
-
value === "ping" ? "pong" : delegate(value),
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
expect(formatter.format("ping")).toBe("pong")
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it("handles delegation to the original formatter", () => {
|
|
153
|
-
const formatter = upperCaseFormatter.wrap((delegate, value) =>
|
|
154
|
-
value === "ping" ? "pong" : delegate(value),
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
expect(formatter.format("foo")).toBe("FOO")
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it("sets the `innerFormatter` property", () => {
|
|
161
|
-
const wrappedFormatter = upperCaseFormatter.wrap((delegate, value) => delegate(value))
|
|
162
|
-
expect(wrappedFormatter.innerFormatter).toBe(upperCaseFormatter)
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
it("passes the `primitive` suggestion to `delegate` when using `formatAsPrimitive`", () => {
|
|
166
|
-
const formatter = valueRecordUpperCaseFormatter.wrap((delegate, value) => delegate(value))
|
|
167
|
-
expect(formatter.formatAsPrimitive({ value: "foo" })).toBe("FOO")
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
it("passes suggestions through to `delegate` when not overriden", () => {
|
|
171
|
-
const formatter = valueRecordUpperCaseFormatter.wrap((delegate, value) => delegate(value))
|
|
172
|
-
expect(formatter.format({ value: "foo" }, ["primitive"])).toBe("FOO")
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
it("supports overriding of suggestions for `delegate`", () => {
|
|
176
|
-
const formatter = valueRecordUpperCaseFormatter.wrap((delegate, value) => delegate(value, []))
|
|
177
|
-
expect(formatter.format({ value: "foo" }, ["primitive"])).toEqual({ value: "FOO" })
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it("supports modifying the input structure", () => {
|
|
181
|
-
const formatter = upperCaseFormatter.wrap<ValueRecord>((delegate, { value }) =>
|
|
182
|
-
delegate(value),
|
|
183
|
-
)
|
|
184
|
-
|
|
185
|
-
expect(formatter.format({ value: "foo" })).toBe("FOO")
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
it("supports modifying the output structure", () => {
|
|
189
|
-
const formatter = upperCaseFormatter.wrap<ValueRecord, ValueRecord>(
|
|
190
|
-
(delegate, { value }) => ({ value: delegate(value) }),
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
expect(formatter.format({ value: "foo" })).toEqual({ value: "FOO" })
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
it("supports modifying the data context structure", () => {
|
|
197
|
-
interface ListContext {
|
|
198
|
-
row: string
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const listFormatter = upperCaseFormatter.wrap<string, string, string, ListContext>(
|
|
202
|
-
(delegate, value, suggestions, { row }) => `${row}: ${delegate(value)}`,
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
interface GridContext extends ListContext {
|
|
206
|
-
column: string
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
expect(listFormatter.format("foo", [], { row: "A" })).toBe("A: FOO")
|
|
210
|
-
|
|
211
|
-
const gridFormatter = listFormatter.wrap<string, string, string, GridContext>(
|
|
212
|
-
(delegate, value, suggestions, { column }) => delegate(value).replace(":", `${column}:`),
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
expect(gridFormatter.format("foo", [], { row: "B", column: "1" })).toBe("B1: FOO")
|
|
216
|
-
})
|
|
217
|
-
})
|
|
218
|
-
})
|
package/src/makeFormatter.ts
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
type PrimitiveSuggestion = "primitive" | "comparable"
|
|
2
|
-
|
|
3
|
-
type Suggestion =
|
|
4
|
-
| PrimitiveSuggestion
|
|
5
|
-
| "abbreviated"
|
|
6
|
-
| "as-icon"
|
|
7
|
-
/**
|
|
8
|
-
* @deprecated Since v0.6.3. Use `"as-icon"` or `"with-icon"` instead.
|
|
9
|
-
*/
|
|
10
|
-
| "icon"
|
|
11
|
-
| "verbose"
|
|
12
|
-
| "with-icon"
|
|
13
|
-
|
|
14
|
-
const ensureFormatSuggestionIntegrity = (suggestions: Suggestion[]): Suggestion[] =>
|
|
15
|
-
suggestions.includes("primitive") || !suggestions.includes("comparable")
|
|
16
|
-
? suggestions
|
|
17
|
-
: ["primitive", ...suggestions]
|
|
18
|
-
|
|
19
|
-
const ensureFormatAsPrimitiveSuggestionIntegrity = (suggestions: Suggestion[]): Suggestion[] =>
|
|
20
|
-
suggestions.includes("primitive") ? suggestions : ["primitive", ...suggestions]
|
|
21
|
-
|
|
22
|
-
type DataContext = Record<string, any>
|
|
23
|
-
|
|
24
|
-
interface FormatterOptions {
|
|
25
|
-
/** Formatter name, useful for debugging or advanced pattern matching. */
|
|
26
|
-
displayName?: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
30
|
-
(
|
|
31
|
-
/** Value to format. */
|
|
32
|
-
value: TInput,
|
|
33
|
-
/** Suggestions passed by the consumer of a formatter. */
|
|
34
|
-
suggestions: Suggestion[],
|
|
35
|
-
/** Additional data context to be used by the formatter. */
|
|
36
|
-
dataContext: Partial<TDataContext>,
|
|
37
|
-
): TOutput | TPrimitiveOutput
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
41
|
-
(
|
|
42
|
-
/** Value to format. */
|
|
43
|
-
value: TInput,
|
|
44
|
-
/** Suggestions the formatter should take note of. */
|
|
45
|
-
suggestions?: Suggestion[],
|
|
46
|
-
/** Additional data context the formatter might find useful. */
|
|
47
|
-
dataContext?: Partial<TDataContext>,
|
|
48
|
-
): TOutput | TPrimitiveOutput
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
interface FormatAsPrimitiveMethod<TInput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
52
|
-
(
|
|
53
|
-
/** Value to format. */
|
|
54
|
-
value: TInput,
|
|
55
|
-
/** Suggestions the formatter should take note of in addition to `primitive`. */
|
|
56
|
-
suggestions?: Suggestion[],
|
|
57
|
-
/** Additional data context the formatter might find useful. */
|
|
58
|
-
dataContext?: Partial<TDataContext>,
|
|
59
|
-
): TPrimitiveOutput
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface FormatChainDefinition<
|
|
63
|
-
TInnerInput,
|
|
64
|
-
TInnerOutput,
|
|
65
|
-
TInnerPrimitiveInput,
|
|
66
|
-
TInnerDataContext extends DataContext,
|
|
67
|
-
TOuterInput,
|
|
68
|
-
TOuterOutput,
|
|
69
|
-
TOuterPrimitiveOutput,
|
|
70
|
-
TOuterDataContext extends DataContext
|
|
71
|
-
> {
|
|
72
|
-
(
|
|
73
|
-
/**
|
|
74
|
-
* The `formatter.format` method which can be used to delegate the formatting
|
|
75
|
-
* to the wrapped formatter. Delegation is simplified so if no suggestions or contextual
|
|
76
|
-
* props are passed, the original ones are used instead.
|
|
77
|
-
*/
|
|
78
|
-
delegate: FormatMethod<TInnerInput, TInnerOutput, TInnerPrimitiveInput, TInnerDataContext>,
|
|
79
|
-
/** Value to format. */
|
|
80
|
-
value: TOuterInput,
|
|
81
|
-
/** Suggestions the formatter should take note of. */
|
|
82
|
-
suggestions: Suggestion[],
|
|
83
|
-
/** Additional data context the formatter might find useful. */
|
|
84
|
-
dataContext: Partial<TOuterDataContext>,
|
|
85
|
-
): TOuterOutput | TOuterPrimitiveOutput
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
type FormatterProps<TInput, TDataContext extends DataContext> = {
|
|
89
|
-
/** Value to format. */
|
|
90
|
-
children: TInput
|
|
91
|
-
/** Suggestions the formatter should take note of. */
|
|
92
|
-
suggestions?: Suggestion[]
|
|
93
|
-
} & Partial<TDataContext>
|
|
94
|
-
|
|
95
|
-
export interface Formatter<
|
|
96
|
-
TInput,
|
|
97
|
-
TOutput,
|
|
98
|
-
TPrimitiveOutput = TOutput,
|
|
99
|
-
TDataContext extends DataContext = DataContext
|
|
100
|
-
> {
|
|
101
|
-
/** Formatter name, useful for debugging or advanced pattern matching. */
|
|
102
|
-
displayName?: string
|
|
103
|
-
/** Formats a value. */
|
|
104
|
-
format: FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext>
|
|
105
|
-
/** Formats a value with the `primitive` suggestion. */
|
|
106
|
-
formatAsPrimitive: FormatAsPrimitiveMethod<TInput, TPrimitiveOutput, TDataContext>
|
|
107
|
-
/** The callee of the `wrap` method used to produce this formatter. */
|
|
108
|
-
innerFormatter?: Formatter<any, any, any, any>
|
|
109
|
-
/**
|
|
110
|
-
* Creates a new formatter from an existing one. Allows overriding of formatter behaviour
|
|
111
|
-
* for certain values.
|
|
112
|
-
*/
|
|
113
|
-
wrap: <
|
|
114
|
-
TNextInput = TInput,
|
|
115
|
-
TNextOutput = TOutput,
|
|
116
|
-
TNextPrimitiveOutput = TPrimitiveOutput,
|
|
117
|
-
TNextDataContext extends TDataContext = TDataContext
|
|
118
|
-
>(
|
|
119
|
-
/**
|
|
120
|
-
* Function used to format the value. Has the same signature as the one passed
|
|
121
|
-
* to `makeFormatter`, except a `delegate` function is passed in the first position.
|
|
122
|
-
* This function can be used to delegate formatting to the original (inner) formatter.
|
|
123
|
-
*/
|
|
124
|
-
nextFormat: FormatChainDefinition<
|
|
125
|
-
TInput,
|
|
126
|
-
TOutput,
|
|
127
|
-
TPrimitiveOutput,
|
|
128
|
-
TDataContext,
|
|
129
|
-
TNextInput,
|
|
130
|
-
TNextOutput,
|
|
131
|
-
TNextPrimitiveOutput,
|
|
132
|
-
TNextDataContext
|
|
133
|
-
>,
|
|
134
|
-
/** New formatter options, replacing the original ones. */
|
|
135
|
-
nextFormatterOptions?: FormatterOptions,
|
|
136
|
-
) => Formatter<TNextInput, TNextOutput, TNextPrimitiveOutput, TNextDataContext>
|
|
137
|
-
/**
|
|
138
|
-
* Backwards-compatible way to use the formatter as a React component.
|
|
139
|
-
*
|
|
140
|
-
* @deprecated Since v0.6.0. Prefer using the `format` method instead.
|
|
141
|
-
*/
|
|
142
|
-
(props: FormatterProps<TInput, TDataContext>): TOutput | TPrimitiveOutput | null
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Creates a new formatter.
|
|
147
|
-
*
|
|
148
|
-
* @param format Function used to format the value.
|
|
149
|
-
* @param formatterOptions Additional options for the formatter.
|
|
150
|
-
*/
|
|
151
|
-
export const makeFormatter = <
|
|
152
|
-
TInput,
|
|
153
|
-
TOutput,
|
|
154
|
-
TPrimitiveOutput = TOutput,
|
|
155
|
-
TDataContext extends DataContext = DataContext
|
|
156
|
-
>(
|
|
157
|
-
format: FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext>,
|
|
158
|
-
formatterOptions?: FormatterOptions,
|
|
159
|
-
): Formatter<TInput, TOutput, TPrimitiveOutput, TDataContext> => {
|
|
160
|
-
const formatter: Formatter<TInput, TOutput, TPrimitiveOutput, TDataContext> = props =>
|
|
161
|
-
format(props.children, props.suggestions ?? [], props) ?? null
|
|
162
|
-
|
|
163
|
-
formatter.displayName = formatterOptions?.displayName
|
|
164
|
-
|
|
165
|
-
formatter.format = (value, suggestions = [], dataContext = {}) =>
|
|
166
|
-
format(value, ensureFormatSuggestionIntegrity(suggestions), dataContext)
|
|
167
|
-
|
|
168
|
-
formatter.formatAsPrimitive = (value, suggestions = [], dataContext = {}) =>
|
|
169
|
-
format(
|
|
170
|
-
value,
|
|
171
|
-
ensureFormatAsPrimitiveSuggestionIntegrity(suggestions),
|
|
172
|
-
dataContext,
|
|
173
|
-
) as TPrimitiveOutput
|
|
174
|
-
|
|
175
|
-
formatter.wrap = <
|
|
176
|
-
TNextInput,
|
|
177
|
-
TNextOutput,
|
|
178
|
-
TNextPrimitiveOutput,
|
|
179
|
-
TNextDataContext extends TDataContext
|
|
180
|
-
>(
|
|
181
|
-
nextFormat: FormatChainDefinition<
|
|
182
|
-
TInput,
|
|
183
|
-
TOutput,
|
|
184
|
-
TPrimitiveOutput,
|
|
185
|
-
TDataContext,
|
|
186
|
-
TNextInput,
|
|
187
|
-
TNextOutput,
|
|
188
|
-
TNextPrimitiveOutput,
|
|
189
|
-
TNextDataContext
|
|
190
|
-
>,
|
|
191
|
-
nextFormatterOptions?: FormatterOptions,
|
|
192
|
-
) => {
|
|
193
|
-
const nextFormatter = makeFormatter<
|
|
194
|
-
TNextInput,
|
|
195
|
-
TNextOutput,
|
|
196
|
-
TNextPrimitiveOutput,
|
|
197
|
-
TNextDataContext
|
|
198
|
-
>((value, suggestions, dataContext) => {
|
|
199
|
-
const delegate: FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext> = (
|
|
200
|
-
delegatedValue,
|
|
201
|
-
delegatedSuggestions,
|
|
202
|
-
delegatedDataContext,
|
|
203
|
-
) =>
|
|
204
|
-
formatter.format(
|
|
205
|
-
delegatedValue,
|
|
206
|
-
delegatedSuggestions ?? suggestions,
|
|
207
|
-
delegatedDataContext ?? dataContext,
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
return nextFormat(delegate, value, suggestions, dataContext)
|
|
211
|
-
}, nextFormatterOptions ?? formatterOptions)
|
|
212
|
-
|
|
213
|
-
nextFormatter.innerFormatter = formatter
|
|
214
|
-
|
|
215
|
-
return nextFormatter
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return formatter
|
|
219
|
-
}
|