@rowsncolumns/spreadsheet-state 29.2.0 → 29.3.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/dist/cjs/api/border.d.ts +1 -1
- package/dist/cjs/api/border.d.ts.map +1 -1
- package/dist/cjs/commands.d.ts +36 -3
- package/dist/cjs/commands.d.ts.map +1 -1
- package/dist/cjs/components/editors/cell-format/alignment-tab.d.ts +27 -0
- package/dist/cjs/components/editors/cell-format/alignment-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/alignment-tab.js +83 -0
- package/dist/cjs/components/editors/cell-format/border-edges.d.ts +42 -0
- package/dist/cjs/components/editors/cell-format/border-edges.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/border-edges.js +118 -0
- package/dist/cjs/components/editors/cell-format/border-tab.d.ts +21 -0
- package/dist/cjs/components/editors/cell-format/border-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/border-tab.js +123 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.d.ts +14 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.js +54 -0
- package/dist/cjs/components/editors/cell-format/font-tab.d.ts +18 -0
- package/dist/cjs/components/editors/cell-format/font-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/font-tab.js +99 -0
- package/dist/cjs/components/editors/cell-format/list-box.d.ts +35 -0
- package/dist/cjs/components/editors/cell-format/list-box.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/list-box.js +37 -0
- package/dist/cjs/components/editors/cell-format/number-formats.d.ts +90 -0
- package/dist/cjs/components/editors/cell-format/number-formats.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/number-formats.js +403 -0
- package/dist/cjs/components/editors/cell-format/number-tab.d.ts +12 -0
- package/dist/cjs/components/editors/cell-format/number-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/number-tab.js +194 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.d.ts +13 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.js +13 -0
- package/dist/cjs/components/editors/cell-format-editor.d.ts +31 -3
- package/dist/cjs/components/editors/cell-format-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/cell-format-editor.js +182 -636
- package/dist/cjs/components/editors/conditional-format-data-bar-options.d.ts +16 -0
- package/dist/cjs/components/editors/conditional-format-data-bar-options.d.ts.map +1 -0
- package/dist/cjs/components/editors/conditional-format-data-bar-options.js +166 -0
- package/dist/cjs/components/editors/conditional-format-editor.d.ts +7 -1
- package/dist/cjs/components/editors/conditional-format-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/conditional-format-editor.js +51 -9
- package/dist/cjs/components/editors/conditional-format-icon-set-options.d.ts +17 -0
- package/dist/cjs/components/editors/conditional-format-icon-set-options.d.ts.map +1 -0
- package/dist/cjs/components/editors/conditional-format-icon-set-options.js +163 -0
- package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts +9 -0
- package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/conditional-format-rule-editor.js +97 -125
- package/dist/cjs/components/editors/sheet-filter.d.ts +20 -9
- package/dist/cjs/components/editors/sheet-filter.d.ts.map +1 -1
- package/dist/cjs/components/editors/sheet-filter.js +44 -12
- package/dist/cjs/hooks/use-conditional-formatting-rules.d.ts +2 -0
- package/dist/cjs/hooks/use-conditional-formatting-rules.d.ts.map +1 -1
- package/dist/cjs/hooks/use-conditional-formatting-rules.js +22 -1
- package/dist/cjs/hooks/use-spreadsheet-state.d.ts +2 -0
- package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
- package/dist/cjs/hooks/use-spreadsheet-state.js +4 -2
- package/dist/cjs/interface/change-border.d.ts.map +1 -1
- package/dist/cjs/interface/change-border.js +8 -1
- package/dist/cjs/interface/conditional-formatting-rules.d.ts +11 -1
- package/dist/cjs/interface/conditional-formatting-rules.d.ts.map +1 -1
- package/dist/cjs/interface/conditional-formatting-rules.js +44 -1
- package/dist/cjs/sheet-cell.d.ts +8 -0
- package/dist/cjs/sheet-cell.d.ts.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/api/border.d.ts +1 -1
- package/dist/esm/api/border.d.ts.map +1 -1
- package/dist/esm/commands.d.ts +36 -3
- package/dist/esm/commands.d.ts.map +1 -1
- package/dist/esm/components/editors/cell-format/alignment-tab.d.ts +27 -0
- package/dist/esm/components/editors/cell-format/alignment-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/alignment-tab.js +81 -0
- package/dist/esm/components/editors/cell-format/border-edges.d.ts +42 -0
- package/dist/esm/components/editors/cell-format/border-edges.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/border-edges.js +79 -0
- package/dist/esm/components/editors/cell-format/border-tab.d.ts +21 -0
- package/dist/esm/components/editors/cell-format/border-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/border-tab.js +103 -0
- package/dist/esm/components/editors/cell-format/fill-tab.d.ts +14 -0
- package/dist/esm/components/editors/cell-format/fill-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/fill-tab.js +49 -0
- package/dist/esm/components/editors/cell-format/font-tab.d.ts +18 -0
- package/dist/esm/components/editors/cell-format/font-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/font-tab.js +88 -0
- package/dist/esm/components/editors/cell-format/list-box.d.ts +35 -0
- package/dist/esm/components/editors/cell-format/list-box.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/list-box.js +30 -0
- package/dist/esm/components/editors/cell-format/number-formats.d.ts +90 -0
- package/dist/esm/components/editors/cell-format/number-formats.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/number-formats.js +383 -0
- package/dist/esm/components/editors/cell-format/number-tab.d.ts +12 -0
- package/dist/esm/components/editors/cell-format/number-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/number-tab.js +165 -0
- package/dist/esm/components/editors/cell-format/protection-tab.d.ts +13 -0
- package/dist/esm/components/editors/cell-format/protection-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/protection-tab.js +9 -0
- package/dist/esm/components/editors/cell-format-editor.d.ts +31 -3
- package/dist/esm/components/editors/cell-format-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/cell-format-editor.js +148 -615
- package/dist/esm/components/editors/conditional-format-data-bar-options.d.ts +16 -0
- package/dist/esm/components/editors/conditional-format-data-bar-options.d.ts.map +1 -0
- package/dist/esm/components/editors/conditional-format-data-bar-options.js +145 -0
- package/dist/esm/components/editors/conditional-format-editor.d.ts +7 -1
- package/dist/esm/components/editors/conditional-format-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/conditional-format-editor.js +39 -8
- package/dist/esm/components/editors/conditional-format-icon-set-options.d.ts +17 -0
- package/dist/esm/components/editors/conditional-format-icon-set-options.d.ts.map +1 -0
- package/dist/esm/components/editors/conditional-format-icon-set-options.js +139 -0
- package/dist/esm/components/editors/conditional-format-rule-editor.d.ts +9 -0
- package/dist/esm/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/conditional-format-rule-editor.js +60 -85
- package/dist/esm/components/editors/sheet-filter.d.ts +20 -9
- package/dist/esm/components/editors/sheet-filter.d.ts.map +1 -1
- package/dist/esm/components/editors/sheet-filter.js +31 -11
- package/dist/esm/hooks/use-conditional-formatting-rules.d.ts +2 -0
- package/dist/esm/hooks/use-conditional-formatting-rules.d.ts.map +1 -1
- package/dist/esm/hooks/use-conditional-formatting-rules.js +19 -1
- package/dist/esm/hooks/use-spreadsheet-state.d.ts +2 -0
- package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
- package/dist/esm/hooks/use-spreadsheet-state.js +4 -2
- package/dist/esm/interface/change-border.d.ts.map +1 -1
- package/dist/esm/interface/change-border.js +8 -1
- package/dist/esm/interface/conditional-formatting-rules.d.ts +11 -1
- package/dist/esm/interface/conditional-formatting-rules.d.ts.map +1 -1
- package/dist/esm/interface/conditional-formatting-rules.js +29 -1
- package/dist/esm/sheet-cell.d.ts +8 -0
- package/dist/esm/sheet-cell.d.ts.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { NumberFormat, NumberFormatType } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
export type NumberCategoryId = "general" | "number" | "currency" | "accounting" | "date" | "time" | "percentage" | "fraction" | "scientific" | "text" | "special" | "custom";
|
|
3
|
+
export type NumberCategory = {
|
|
4
|
+
id: NumberCategoryId;
|
|
5
|
+
name: string;
|
|
6
|
+
type: NumberFormatType;
|
|
7
|
+
description: string;
|
|
8
|
+
};
|
|
9
|
+
/** Excel's category list, in Excel's order. */
|
|
10
|
+
export declare const NUMBER_CATEGORIES: NumberCategory[];
|
|
11
|
+
/** Excel's four "Negative numbers" styles. */
|
|
12
|
+
export type NegativeStyle = "minus" | "red" | "parens" | "redParens";
|
|
13
|
+
export declare const NEGATIVE_STYLES: NegativeStyle[];
|
|
14
|
+
/** Number: decimal places, 1000 separator, negative numbers. */
|
|
15
|
+
export declare const buildNumberPattern: ({ decimals, thousands, negative, }: {
|
|
16
|
+
decimals: number;
|
|
17
|
+
thousands: boolean;
|
|
18
|
+
negative: NegativeStyle;
|
|
19
|
+
}) => string;
|
|
20
|
+
/** Currency: decimal places, symbol, negative numbers. */
|
|
21
|
+
export declare const buildCurrencyPattern: ({ decimals, symbol, negative, }: {
|
|
22
|
+
decimals: number;
|
|
23
|
+
symbol: string;
|
|
24
|
+
negative: NegativeStyle;
|
|
25
|
+
}) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Accounting: decimal places and symbol. The symbol sits at the left edge
|
|
28
|
+
* (`* ` repeats the space to fill the cell), zero shows a dash, and the `_(`
|
|
29
|
+
* / `_)` paddings line the decimal points up across positive and negative.
|
|
30
|
+
*/
|
|
31
|
+
export declare const buildAccountingPattern: ({ decimals, symbol, }: {
|
|
32
|
+
decimals: number;
|
|
33
|
+
symbol: string;
|
|
34
|
+
}) => string;
|
|
35
|
+
export declare const buildPercentPattern: (decimals: number) => string;
|
|
36
|
+
export declare const buildScientificPattern: (decimals: number) => string;
|
|
37
|
+
/** Excel's Currency / Accounting symbol list (a representative subset). */
|
|
38
|
+
export declare const CURRENCY_SYMBOLS: {
|
|
39
|
+
symbol: string;
|
|
40
|
+
label: string;
|
|
41
|
+
}[];
|
|
42
|
+
export declare const FRACTION_TYPES: {
|
|
43
|
+
label: string;
|
|
44
|
+
pattern: string;
|
|
45
|
+
}[];
|
|
46
|
+
/** Excel's Special types for English (United States). */
|
|
47
|
+
export declare const SPECIAL_TYPES: {
|
|
48
|
+
label: string;
|
|
49
|
+
pattern: string;
|
|
50
|
+
}[];
|
|
51
|
+
/** Locales offered by the Date / Time / Special "Locale (location)" list. */
|
|
52
|
+
export type FormatLocale = {
|
|
53
|
+
/** BCP-47 tag. */
|
|
54
|
+
tag: string;
|
|
55
|
+
label: string;
|
|
56
|
+
/** Windows LCID (hex) written as Excel's `[$-xxxx]` locale prefix. */
|
|
57
|
+
lcid: string;
|
|
58
|
+
/** Day before month in the short date. */
|
|
59
|
+
dayFirst: boolean;
|
|
60
|
+
};
|
|
61
|
+
export declare const FORMAT_LOCALES: FormatLocale[];
|
|
62
|
+
export declare const findFormatLocale: (tag: string | undefined) => FormatLocale;
|
|
63
|
+
/**
|
|
64
|
+
* The Date / Time types for a locale. The default locale's codes are written
|
|
65
|
+
* bare (they follow the workbook); another locale's carry Excel's
|
|
66
|
+
* `[$-lcid]` prefix so the cell keeps that locale's names and order.
|
|
67
|
+
*/
|
|
68
|
+
export declare const getDateTimeTypes: (kind: "date" | "time", locale: FormatLocale, defaultLocale: FormatLocale) => string[];
|
|
69
|
+
/** The locale a format code's `[$-lcid]` prefix names, if any. */
|
|
70
|
+
export declare const getPatternLocale: (pattern: string | null | undefined) => FormatLocale | undefined;
|
|
71
|
+
/** The pieces the Number / Currency options read back off a code. */
|
|
72
|
+
export declare const parseNumericPattern: (pattern: string | null | undefined) => {
|
|
73
|
+
decimals: number;
|
|
74
|
+
thousands: boolean;
|
|
75
|
+
negative: NegativeStyle;
|
|
76
|
+
symbol: string;
|
|
77
|
+
};
|
|
78
|
+
/** Which category a cell's number format opens the Number tab on. */
|
|
79
|
+
export declare const detectCategory: (format: NumberFormat | null | undefined) => NumberCategoryId;
|
|
80
|
+
/** The format a category gets when it is first picked (Excel's defaults). */
|
|
81
|
+
export declare const defaultFormatForCategory: (id: NumberCategoryId, { currencySymbol, locale, defaultLocale, }: {
|
|
82
|
+
currencySymbol: string;
|
|
83
|
+
locale: FormatLocale;
|
|
84
|
+
defaultLocale: FormatLocale;
|
|
85
|
+
}) => NumberFormat | null;
|
|
86
|
+
/** Excel's Custom type list (the built-in codes). */
|
|
87
|
+
export declare const CUSTOM_PATTERNS: string[];
|
|
88
|
+
/** The NumberFormatType a typed custom code is closest to. */
|
|
89
|
+
export declare const inferTypeFromPattern: (pattern: string) => NumberFormatType;
|
|
90
|
+
//# sourceMappingURL=number-formats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-formats.d.ts","sourceRoot":"","sources":["../../../../../components/editors/cell-format/number-formats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/** Excel's category list, in Excel's order. */
|
|
2
|
+
export const NUMBER_CATEGORIES = [
|
|
3
|
+
{
|
|
4
|
+
id: "general",
|
|
5
|
+
name: "General",
|
|
6
|
+
type: "GENERAL",
|
|
7
|
+
description: "General format cells have no specific number format.",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: "number",
|
|
11
|
+
name: "Number",
|
|
12
|
+
type: "NUMBER",
|
|
13
|
+
description: "Number is used for general display of numbers. Currency and Accounting offer specialized formatting for monetary value.",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "currency",
|
|
17
|
+
name: "Currency",
|
|
18
|
+
type: "CURRENCY",
|
|
19
|
+
description: "Currency formats are used for general monetary values. Use Accounting formats to align decimal points in a column.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "accounting",
|
|
23
|
+
name: "Accounting",
|
|
24
|
+
type: "ACCOUNTING",
|
|
25
|
+
description: "Accounting formats line up the currency symbols and decimal points in a column.",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "date",
|
|
29
|
+
name: "Date",
|
|
30
|
+
type: "DATE",
|
|
31
|
+
description: "Date formats display date and time serial numbers as date values.",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "time",
|
|
35
|
+
name: "Time",
|
|
36
|
+
type: "DATE_TIME",
|
|
37
|
+
description: "Time formats display date and time serial numbers as time values.",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "percentage",
|
|
41
|
+
name: "Percentage",
|
|
42
|
+
type: "PERCENT",
|
|
43
|
+
description: "Percentage formats multiply the cell value by 100 and display the result with a percent symbol.",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "fraction",
|
|
47
|
+
name: "Fraction",
|
|
48
|
+
type: "FRACTION",
|
|
49
|
+
description: "Fraction formats display a number as a fraction.",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "scientific",
|
|
53
|
+
name: "Scientific",
|
|
54
|
+
type: "SCIENTIFIC",
|
|
55
|
+
description: "Scientific formats display a number in exponential notation.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "text",
|
|
59
|
+
name: "Text",
|
|
60
|
+
type: "TEXT",
|
|
61
|
+
description: "Text format cells are treated as text even when a number is in the cell. The cell is displayed exactly as entered.",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "special",
|
|
65
|
+
name: "Special",
|
|
66
|
+
type: "SPECIAL",
|
|
67
|
+
description: "Special formats are useful for tracking list and database values.",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "custom",
|
|
71
|
+
name: "Custom",
|
|
72
|
+
type: "NUMBER",
|
|
73
|
+
description: "Type the number format code, using one of the existing codes as a starting point.",
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
export const NEGATIVE_STYLES = [
|
|
77
|
+
"minus",
|
|
78
|
+
"red",
|
|
79
|
+
"parens",
|
|
80
|
+
"redParens",
|
|
81
|
+
];
|
|
82
|
+
const digits = (decimals, thousands) => {
|
|
83
|
+
const d = Math.max(0, Math.min(30, Math.floor(decimals)));
|
|
84
|
+
const base = thousands ? "#,##0" : "0";
|
|
85
|
+
return d > 0 ? `${base}.${"0".repeat(d)}` : base;
|
|
86
|
+
};
|
|
87
|
+
/** `prefix` wraps a currency symbol in quotes so it never reads as a code. */
|
|
88
|
+
const symbolPrefix = (symbol) => symbol ? `"${symbol.replace(/"/g, "")}"` : "";
|
|
89
|
+
const withNegative = (positive, style) => {
|
|
90
|
+
switch (style) {
|
|
91
|
+
case "red":
|
|
92
|
+
return `${positive};[Red]${positive}`;
|
|
93
|
+
case "parens":
|
|
94
|
+
return `${positive}_);(${positive})`;
|
|
95
|
+
case "redParens":
|
|
96
|
+
return `${positive}_);[Red](${positive})`;
|
|
97
|
+
default:
|
|
98
|
+
return positive;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
/** Number: decimal places, 1000 separator, negative numbers. */
|
|
102
|
+
export const buildNumberPattern = ({ decimals, thousands, negative, }) => withNegative(digits(decimals, thousands), negative);
|
|
103
|
+
/** Currency: decimal places, symbol, negative numbers. */
|
|
104
|
+
export const buildCurrencyPattern = ({ decimals, symbol, negative, }) => withNegative(`${symbolPrefix(symbol)}${digits(decimals, true)}`, negative);
|
|
105
|
+
/**
|
|
106
|
+
* Accounting: decimal places and symbol. The symbol sits at the left edge
|
|
107
|
+
* (`* ` repeats the space to fill the cell), zero shows a dash, and the `_(`
|
|
108
|
+
* / `_)` paddings line the decimal points up across positive and negative.
|
|
109
|
+
*/
|
|
110
|
+
export const buildAccountingPattern = ({ decimals, symbol, }) => {
|
|
111
|
+
const d = Math.max(0, Math.min(30, Math.floor(decimals)));
|
|
112
|
+
const num = digits(d, true);
|
|
113
|
+
const sym = symbolPrefix(symbol);
|
|
114
|
+
const zero = d > 0 ? `"-"${"?".repeat(d)}` : `"-"`;
|
|
115
|
+
return `_(${sym}* ${num}_);_(${sym}* \\(${num}\\);_(${sym}* ${zero}_);_(@_)`;
|
|
116
|
+
};
|
|
117
|
+
export const buildPercentPattern = (decimals) => `${digits(decimals, false)}%`;
|
|
118
|
+
export const buildScientificPattern = (decimals) => `${digits(decimals, false)}E+00`;
|
|
119
|
+
/** Excel's Currency / Accounting symbol list (a representative subset). */
|
|
120
|
+
export const CURRENCY_SYMBOLS = [
|
|
121
|
+
{ symbol: "", label: "None" },
|
|
122
|
+
{ symbol: "$", label: "$" },
|
|
123
|
+
{ symbol: "€", label: "€ Euro" },
|
|
124
|
+
{ symbol: "£", label: "£ English (United Kingdom)" },
|
|
125
|
+
{ symbol: "¥", label: "¥ Japanese" },
|
|
126
|
+
{ symbol: "₹", label: "₹ English (India)" },
|
|
127
|
+
{ symbol: "CHF", label: "CHF Swiss" },
|
|
128
|
+
{ symbol: "kr", label: "kr Swedish" },
|
|
129
|
+
{ symbol: "R$", label: "R$ Portuguese (Brazil)" },
|
|
130
|
+
{ symbol: "₩", label: "₩ Korean" },
|
|
131
|
+
];
|
|
132
|
+
export const FRACTION_TYPES = [
|
|
133
|
+
{ label: "Up to one digit (1/4)", pattern: "# ?/?" },
|
|
134
|
+
{ label: "Up to two digits (21/25)", pattern: "# ??/??" },
|
|
135
|
+
{ label: "Up to three digits (312/943)", pattern: "# ???/???" },
|
|
136
|
+
{ label: "As halves (1/2)", pattern: "# ?/2" },
|
|
137
|
+
{ label: "As quarters (2/4)", pattern: "# ?/4" },
|
|
138
|
+
{ label: "As eighths (4/8)", pattern: "# ?/8" },
|
|
139
|
+
{ label: "As sixteenths (8/16)", pattern: "# ??/16" },
|
|
140
|
+
{ label: "As tenths (3/10)", pattern: "# ?/10" },
|
|
141
|
+
{ label: "As hundredths (30/100)", pattern: "# ??/100" },
|
|
142
|
+
];
|
|
143
|
+
/** Excel's Special types for English (United States). */
|
|
144
|
+
export const SPECIAL_TYPES = [
|
|
145
|
+
{ label: "Zip Code", pattern: "00000" },
|
|
146
|
+
{ label: "Zip Code + 4", pattern: "00000-0000" },
|
|
147
|
+
{ label: "Phone Number", pattern: "[<=9999999]###-####;(###) ###-####" },
|
|
148
|
+
{ label: "Social Security Number", pattern: "000-00-0000" },
|
|
149
|
+
];
|
|
150
|
+
export const FORMAT_LOCALES = [
|
|
151
|
+
{ tag: "en-US", label: "English (United States)", lcid: "409", dayFirst: false },
|
|
152
|
+
{ tag: "en-GB", label: "English (United Kingdom)", lcid: "809", dayFirst: true },
|
|
153
|
+
{ tag: "en-IN", label: "English (India)", lcid: "4009", dayFirst: true },
|
|
154
|
+
{ tag: "en-AU", label: "English (Australia)", lcid: "C09", dayFirst: true },
|
|
155
|
+
{ tag: "en-CA", label: "English (Canada)", lcid: "1009", dayFirst: true },
|
|
156
|
+
{ tag: "fr-FR", label: "French (France)", lcid: "40C", dayFirst: true },
|
|
157
|
+
{ tag: "de-DE", label: "German (Germany)", lcid: "407", dayFirst: true },
|
|
158
|
+
{ tag: "es-ES", label: "Spanish (Spain)", lcid: "C0A", dayFirst: true },
|
|
159
|
+
{ tag: "it-IT", label: "Italian (Italy)", lcid: "410", dayFirst: true },
|
|
160
|
+
{ tag: "ja-JP", label: "Japanese", lcid: "411", dayFirst: false },
|
|
161
|
+
{ tag: "zh-CN", label: "Chinese (PRC)", lcid: "804", dayFirst: false },
|
|
162
|
+
];
|
|
163
|
+
export const findFormatLocale = (tag) => FORMAT_LOCALES.find((l) => l.tag === tag) ??
|
|
164
|
+
FORMAT_LOCALES.find((l) => tag && l.tag.split("-")[0] === tag.split("-")[0]) ??
|
|
165
|
+
FORMAT_LOCALES[0];
|
|
166
|
+
/** Excel's Date types for English (United States). */
|
|
167
|
+
const DATE_TYPES_US = [
|
|
168
|
+
"m/d/yyyy",
|
|
169
|
+
"dddd, mmmm d, yyyy",
|
|
170
|
+
"m/d;@",
|
|
171
|
+
"m/d/yy;@",
|
|
172
|
+
"mm/dd/yy;@",
|
|
173
|
+
"d-mmm;@",
|
|
174
|
+
"d-mmm-yy;@",
|
|
175
|
+
"dd-mmm-yy;@",
|
|
176
|
+
"mmm-yy;@",
|
|
177
|
+
"mmmm-yy;@",
|
|
178
|
+
"mmmm d, yyyy;@",
|
|
179
|
+
"m/d/yy h:mm AM/PM;@",
|
|
180
|
+
"m/d/yy h:mm;@",
|
|
181
|
+
"mmmmm;@",
|
|
182
|
+
"mmmmm-yy;@",
|
|
183
|
+
"m/d/yyyy;@",
|
|
184
|
+
"d-mmm-yyyy;@",
|
|
185
|
+
];
|
|
186
|
+
/** Excel's Time types for English (United States). */
|
|
187
|
+
const TIME_TYPES_US = [
|
|
188
|
+
"h:mm:ss AM/PM",
|
|
189
|
+
"h:mm;@",
|
|
190
|
+
"h:mm AM/PM;@",
|
|
191
|
+
"h:mm:ss;@",
|
|
192
|
+
"h:mm:ss AM/PM;@",
|
|
193
|
+
"mm:ss.0;@",
|
|
194
|
+
"[h]:mm:ss;@",
|
|
195
|
+
"m/d/yy h:mm AM/PM;@",
|
|
196
|
+
"m/d/yy h:mm;@",
|
|
197
|
+
];
|
|
198
|
+
/** A month-first numeric date code reordered day-first (`m/d/yy` → `d/m/yy`). */
|
|
199
|
+
const dayFirst = (pattern) => pattern.replace(/\b(m{1,2})\/(d{1,2})\b/g, "$2/$1");
|
|
200
|
+
/**
|
|
201
|
+
* The Date / Time types for a locale. The default locale's codes are written
|
|
202
|
+
* bare (they follow the workbook); another locale's carry Excel's
|
|
203
|
+
* `[$-lcid]` prefix so the cell keeps that locale's names and order.
|
|
204
|
+
*/
|
|
205
|
+
export const getDateTimeTypes = (kind, locale, defaultLocale) => {
|
|
206
|
+
const base = kind === "date" ? DATE_TYPES_US : TIME_TYPES_US;
|
|
207
|
+
const ordered = locale.dayFirst ? base.map(dayFirst) : base;
|
|
208
|
+
if (locale.tag === defaultLocale.tag)
|
|
209
|
+
return ordered;
|
|
210
|
+
return ordered.map((p) => `[$-${locale.lcid}]${p}`);
|
|
211
|
+
};
|
|
212
|
+
const LOCALE_PREFIX = /^\[\$-([0-9A-Fa-f]+)\]/;
|
|
213
|
+
/** The locale a format code's `[$-lcid]` prefix names, if any. */
|
|
214
|
+
export const getPatternLocale = (pattern) => {
|
|
215
|
+
const lcid = pattern?.match(LOCALE_PREFIX)?.[1]?.toUpperCase();
|
|
216
|
+
return lcid
|
|
217
|
+
? FORMAT_LOCALES.find((l) => l.lcid.toUpperCase() === lcid)
|
|
218
|
+
: undefined;
|
|
219
|
+
};
|
|
220
|
+
/** The pieces the Number / Currency options read back off a code. */
|
|
221
|
+
export const parseNumericPattern = (pattern) => {
|
|
222
|
+
const p = pattern ?? "";
|
|
223
|
+
const first = p.split(";")[0] ?? "";
|
|
224
|
+
const decimals = first.match(/\.(0+)/)?.[1]?.length ?? 0;
|
|
225
|
+
const thousands = /#,##0/.test(first);
|
|
226
|
+
const sections = p.split(";");
|
|
227
|
+
const second = sections[1] ?? "";
|
|
228
|
+
const negative = !second
|
|
229
|
+
? "minus"
|
|
230
|
+
: second.includes("[Red]")
|
|
231
|
+
? second.includes("(")
|
|
232
|
+
? "redParens"
|
|
233
|
+
: "red"
|
|
234
|
+
: second.includes("(")
|
|
235
|
+
? "parens"
|
|
236
|
+
: "minus";
|
|
237
|
+
const symbol = first.match(/"([^"]+)"/)?.[1] ?? "";
|
|
238
|
+
return { decimals, thousands, negative, symbol };
|
|
239
|
+
};
|
|
240
|
+
/** Which category a cell's number format opens the Number tab on. */
|
|
241
|
+
export const detectCategory = (format) => {
|
|
242
|
+
const pattern = format?.pattern ?? "";
|
|
243
|
+
if (SPECIAL_TYPES.some((t) => t.pattern === pattern))
|
|
244
|
+
return "special";
|
|
245
|
+
switch (format?.type) {
|
|
246
|
+
case undefined:
|
|
247
|
+
case "GENERAL":
|
|
248
|
+
return pattern && pattern !== "General" ? "custom" : "general";
|
|
249
|
+
case "NUMBER":
|
|
250
|
+
return "number";
|
|
251
|
+
case "CURRENCY":
|
|
252
|
+
return pattern.startsWith("_(") ? "accounting" : "currency";
|
|
253
|
+
case "ACCOUNTING":
|
|
254
|
+
return "accounting";
|
|
255
|
+
case "DATE":
|
|
256
|
+
return "date";
|
|
257
|
+
case "TIME":
|
|
258
|
+
case "DATE_TIME":
|
|
259
|
+
return "time";
|
|
260
|
+
case "PERCENT":
|
|
261
|
+
return "percentage";
|
|
262
|
+
case "FRACTION":
|
|
263
|
+
return "fraction";
|
|
264
|
+
case "SCIENTIFIC":
|
|
265
|
+
return "scientific";
|
|
266
|
+
case "TEXT":
|
|
267
|
+
return "text";
|
|
268
|
+
case "SPECIAL":
|
|
269
|
+
return "special";
|
|
270
|
+
default:
|
|
271
|
+
return "custom";
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
/** The format a category gets when it is first picked (Excel's defaults). */
|
|
275
|
+
export const defaultFormatForCategory = (id, { currencySymbol, locale, defaultLocale, }) => {
|
|
276
|
+
switch (id) {
|
|
277
|
+
case "general":
|
|
278
|
+
return null;
|
|
279
|
+
case "number":
|
|
280
|
+
return {
|
|
281
|
+
type: "NUMBER",
|
|
282
|
+
pattern: buildNumberPattern({
|
|
283
|
+
decimals: 2,
|
|
284
|
+
thousands: false,
|
|
285
|
+
negative: "minus",
|
|
286
|
+
}),
|
|
287
|
+
};
|
|
288
|
+
case "currency":
|
|
289
|
+
return {
|
|
290
|
+
type: "CURRENCY",
|
|
291
|
+
pattern: buildCurrencyPattern({
|
|
292
|
+
decimals: 2,
|
|
293
|
+
symbol: currencySymbol,
|
|
294
|
+
negative: "minus",
|
|
295
|
+
}),
|
|
296
|
+
};
|
|
297
|
+
case "accounting":
|
|
298
|
+
return {
|
|
299
|
+
type: "ACCOUNTING",
|
|
300
|
+
pattern: buildAccountingPattern({ decimals: 2, symbol: currencySymbol }),
|
|
301
|
+
};
|
|
302
|
+
case "date":
|
|
303
|
+
return {
|
|
304
|
+
type: "DATE",
|
|
305
|
+
pattern: getDateTimeTypes("date", locale, defaultLocale)[0],
|
|
306
|
+
};
|
|
307
|
+
case "time":
|
|
308
|
+
return {
|
|
309
|
+
type: "DATE_TIME",
|
|
310
|
+
pattern: getDateTimeTypes("time", locale, defaultLocale)[0],
|
|
311
|
+
};
|
|
312
|
+
case "percentage":
|
|
313
|
+
return { type: "PERCENT", pattern: buildPercentPattern(2) };
|
|
314
|
+
case "fraction":
|
|
315
|
+
return { type: "FRACTION", pattern: FRACTION_TYPES[0].pattern };
|
|
316
|
+
case "scientific":
|
|
317
|
+
return { type: "SCIENTIFIC", pattern: buildScientificPattern(2) };
|
|
318
|
+
case "text":
|
|
319
|
+
return { type: "TEXT", pattern: "@" };
|
|
320
|
+
case "special":
|
|
321
|
+
return { type: "SPECIAL", pattern: SPECIAL_TYPES[0].pattern };
|
|
322
|
+
case "custom":
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
/** Excel's Custom type list (the built-in codes). */
|
|
327
|
+
export const CUSTOM_PATTERNS = [
|
|
328
|
+
"General",
|
|
329
|
+
"0",
|
|
330
|
+
"0.00",
|
|
331
|
+
"#,##0",
|
|
332
|
+
"#,##0.00",
|
|
333
|
+
"#,##0_);(#,##0)",
|
|
334
|
+
"#,##0_);[Red](#,##0)",
|
|
335
|
+
"#,##0.00_);(#,##0.00)",
|
|
336
|
+
"#,##0.00_);[Red](#,##0.00)",
|
|
337
|
+
'"$"#,##0_);("$"#,##0)',
|
|
338
|
+
'"$"#,##0_);[Red]("$"#,##0)',
|
|
339
|
+
'"$"#,##0.00_);("$"#,##0.00)',
|
|
340
|
+
'"$"#,##0.00_);[Red]("$"#,##0.00)',
|
|
341
|
+
"0%",
|
|
342
|
+
"0.00%",
|
|
343
|
+
"0.00E+00",
|
|
344
|
+
"##0.0E+0",
|
|
345
|
+
"# ?/?",
|
|
346
|
+
"# ??/??",
|
|
347
|
+
"m/d/yyyy",
|
|
348
|
+
"d-mmm-yy",
|
|
349
|
+
"d-mmm",
|
|
350
|
+
"mmm-yy",
|
|
351
|
+
"h:mm AM/PM",
|
|
352
|
+
"h:mm:ss AM/PM",
|
|
353
|
+
"h:mm",
|
|
354
|
+
"h:mm:ss",
|
|
355
|
+
"m/d/yyyy h:mm",
|
|
356
|
+
"mm:ss",
|
|
357
|
+
"mm:ss.0",
|
|
358
|
+
"@",
|
|
359
|
+
"[h]:mm:ss",
|
|
360
|
+
'_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)',
|
|
361
|
+
'_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)',
|
|
362
|
+
'_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)',
|
|
363
|
+
'_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)',
|
|
364
|
+
];
|
|
365
|
+
/** The NumberFormatType a typed custom code is closest to. */
|
|
366
|
+
export const inferTypeFromPattern = (pattern) => {
|
|
367
|
+
const p = pattern.replace(/"[^"]*"/g, "").replace(/\[[^\]]*\]/g, "");
|
|
368
|
+
if (!pattern || pattern === "General")
|
|
369
|
+
return "GENERAL";
|
|
370
|
+
if (p === "@")
|
|
371
|
+
return "TEXT";
|
|
372
|
+
if (/[yd]/i.test(p) || /m{3,}/i.test(p))
|
|
373
|
+
return "DATE";
|
|
374
|
+
if (/[hs]/i.test(p) || /AM\/PM/i.test(p))
|
|
375
|
+
return "DATE_TIME";
|
|
376
|
+
if (/E[+-]/i.test(p))
|
|
377
|
+
return "SCIENTIFIC";
|
|
378
|
+
if (p.includes("%"))
|
|
379
|
+
return "PERCENT";
|
|
380
|
+
if (/\?\/[?\d]/.test(p))
|
|
381
|
+
return "FRACTION";
|
|
382
|
+
return "NUMBER";
|
|
383
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NumberFormat } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import React from "react";
|
|
3
|
+
export type NumberTabProps = {
|
|
4
|
+
numberFormat: NumberFormat | null | undefined;
|
|
5
|
+
onChange(numberFormat: NumberFormat | null): void;
|
|
6
|
+
sampleValue: unknown;
|
|
7
|
+
locale?: string;
|
|
8
|
+
currencySymbol: string;
|
|
9
|
+
};
|
|
10
|
+
/** Format Cells → Number. */
|
|
11
|
+
export declare const NumberTab: ({ numberFormat, onChange, sampleValue, locale, currencySymbol, }: NumberTabProps) => React.JSX.Element;
|
|
12
|
+
//# sourceMappingURL=number-tab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-tab.d.ts","sourceRoot":"","sources":["../../../../../components/editors/cell-format/number-tab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAG9D,OAAO,KAA4B,MAAM,OAAO,CAAC;AA6CjD,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAAC;IAClD,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,6BAA6B;AAC7B,eAAO,MAAM,SAAS,GAAI,kEAMvB,cAAc,sBAiThB,CAAC"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { Input } from "@rowsncolumns/ui";
|
|
2
|
+
import { ssfFormat, ssfFormatColor } from "@rowsncolumns/utils";
|
|
3
|
+
import React, { useMemo, useState } from "react";
|
|
4
|
+
import { CheckboxField, ListBox, SelectField } from "./list-box";
|
|
5
|
+
import { buildAccountingPattern, buildCurrencyPattern, buildNumberPattern, buildPercentPattern, buildScientificPattern, CURRENCY_SYMBOLS, CUSTOM_PATTERNS, defaultFormatForCategory, detectCategory, findFormatLocale, FORMAT_LOCALES, FRACTION_TYPES, getDateTimeTypes, getPatternLocale, inferTypeFromPattern, NEGATIVE_STYLES, NUMBER_CATEGORIES, parseNumericPattern, SPECIAL_TYPES, } from "./number-formats";
|
|
6
|
+
const SAMPLE_NEGATIVE = -1234.1;
|
|
7
|
+
const render = (pattern, value) => {
|
|
8
|
+
try {
|
|
9
|
+
return ssfFormat(pattern, value) || " ";
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return " ";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const colorOf = (pattern, value) => {
|
|
16
|
+
try {
|
|
17
|
+
return ssfFormatColor(pattern, value);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
/** Format Cells → Number. */
|
|
24
|
+
export const NumberTab = ({ numberFormat, onChange, sampleValue, locale, currencySymbol, }) => {
|
|
25
|
+
const defaultLocale = findFormatLocale(locale);
|
|
26
|
+
const [category, setCategory] = useState(() => detectCategory(numberFormat));
|
|
27
|
+
const [formatLocale, setFormatLocale] = useState(() => getPatternLocale(numberFormat?.pattern) ?? defaultLocale);
|
|
28
|
+
const pattern = numberFormat?.pattern ?? "General";
|
|
29
|
+
const parsed = parseNumericPattern(numberFormat?.pattern);
|
|
30
|
+
const definition = NUMBER_CATEGORIES.find((c) => c.id === category);
|
|
31
|
+
const sample = render(pattern, sampleValue);
|
|
32
|
+
const pickCategory = (id) => {
|
|
33
|
+
setCategory(id);
|
|
34
|
+
if (id === "custom")
|
|
35
|
+
return;
|
|
36
|
+
onChange(defaultFormatForCategory(id, {
|
|
37
|
+
currencySymbol,
|
|
38
|
+
locale: formatLocale,
|
|
39
|
+
defaultLocale,
|
|
40
|
+
}));
|
|
41
|
+
};
|
|
42
|
+
const dateTimeTypes = useMemo(() => category === "date" || category === "time"
|
|
43
|
+
? getDateTimeTypes(category, formatLocale, defaultLocale)
|
|
44
|
+
: [], [category, formatLocale, defaultLocale]);
|
|
45
|
+
const decimalsField = (onDecimals) => (React.createElement("label", { className: "flex flex-col gap-1 font-system text-sm" },
|
|
46
|
+
"Decimal places",
|
|
47
|
+
React.createElement(Input, { "aria-label": "Decimal places", type: "number", min: 0, max: 30, className: "text-xs", value: parsed.decimals, onChange: (event) => {
|
|
48
|
+
const n = parseInt(event.target.value, 10);
|
|
49
|
+
if (Number.isFinite(n))
|
|
50
|
+
onDecimals(Math.max(0, Math.min(30, n)));
|
|
51
|
+
} })));
|
|
52
|
+
const symbolField = (onSymbol) => (React.createElement(SelectField, { label: "Symbol", value: parsed.symbol, options: CURRENCY_SYMBOLS.map((s) => ({ value: s.symbol, label: s.label })), onChange: onSymbol }));
|
|
53
|
+
const negativeList = (build, selected) => (React.createElement("div", { className: "flex flex-col gap-1" },
|
|
54
|
+
React.createElement("span", { className: "font-system text-sm" }, "Negative numbers"),
|
|
55
|
+
React.createElement(ListBox, { label: "Negative numbers", value: selected, items: NEGATIVE_STYLES.map((style) => {
|
|
56
|
+
const p = build(style);
|
|
57
|
+
return {
|
|
58
|
+
value: style,
|
|
59
|
+
label: (React.createElement("span", { style: { color: colorOf(p, SAMPLE_NEGATIVE) } }, render(p, SAMPLE_NEGATIVE))),
|
|
60
|
+
};
|
|
61
|
+
}), onChange: (style) => onChange({ type: numberFormat?.type ?? "NUMBER", pattern: build(style) }) })));
|
|
62
|
+
const localeField = (React.createElement(SelectField, { label: "Locale (location)", value: formatLocale.tag, options: FORMAT_LOCALES.map((l) => ({ value: l.tag, label: l.label })), onChange: (tag) => {
|
|
63
|
+
const next = findFormatLocale(tag);
|
|
64
|
+
setFormatLocale(next);
|
|
65
|
+
if (category === "date" || category === "time") {
|
|
66
|
+
onChange({
|
|
67
|
+
type: category === "date" ? "DATE" : "DATE_TIME",
|
|
68
|
+
pattern: getDateTimeTypes(category, next, defaultLocale)[0],
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
} }));
|
|
72
|
+
let options = null;
|
|
73
|
+
switch (category) {
|
|
74
|
+
case "number":
|
|
75
|
+
options = (React.createElement(React.Fragment, null,
|
|
76
|
+
decimalsField((decimals) => onChange({
|
|
77
|
+
type: "NUMBER",
|
|
78
|
+
pattern: buildNumberPattern({ ...parsed, decimals }),
|
|
79
|
+
})),
|
|
80
|
+
React.createElement(CheckboxField, { label: "Use 1000 Separator (,)", checked: parsed.thousands, onChange: (thousands) => onChange({
|
|
81
|
+
type: "NUMBER",
|
|
82
|
+
pattern: buildNumberPattern({ ...parsed, thousands }),
|
|
83
|
+
}) }),
|
|
84
|
+
negativeList((negative) => buildNumberPattern({ ...parsed, negative }), parsed.negative)));
|
|
85
|
+
break;
|
|
86
|
+
case "currency":
|
|
87
|
+
options = (React.createElement(React.Fragment, null,
|
|
88
|
+
decimalsField((decimals) => onChange({
|
|
89
|
+
type: "CURRENCY",
|
|
90
|
+
pattern: buildCurrencyPattern({ ...parsed, decimals }),
|
|
91
|
+
})),
|
|
92
|
+
symbolField((symbol) => onChange({
|
|
93
|
+
type: "CURRENCY",
|
|
94
|
+
pattern: buildCurrencyPattern({ ...parsed, symbol }),
|
|
95
|
+
})),
|
|
96
|
+
negativeList((negative) => buildCurrencyPattern({ ...parsed, negative }), parsed.negative)));
|
|
97
|
+
break;
|
|
98
|
+
case "accounting":
|
|
99
|
+
options = (React.createElement(React.Fragment, null,
|
|
100
|
+
decimalsField((decimals) => onChange({
|
|
101
|
+
type: "ACCOUNTING",
|
|
102
|
+
pattern: buildAccountingPattern({ ...parsed, decimals }),
|
|
103
|
+
})),
|
|
104
|
+
symbolField((symbol) => onChange({
|
|
105
|
+
type: "ACCOUNTING",
|
|
106
|
+
pattern: buildAccountingPattern({ ...parsed, symbol }),
|
|
107
|
+
}))));
|
|
108
|
+
break;
|
|
109
|
+
case "percentage":
|
|
110
|
+
options = decimalsField((decimals) => onChange({ type: "PERCENT", pattern: buildPercentPattern(decimals) }));
|
|
111
|
+
break;
|
|
112
|
+
case "scientific":
|
|
113
|
+
options = decimalsField((decimals) => onChange({ type: "SCIENTIFIC", pattern: buildScientificPattern(decimals) }));
|
|
114
|
+
break;
|
|
115
|
+
case "date":
|
|
116
|
+
case "time":
|
|
117
|
+
options = (React.createElement(React.Fragment, null,
|
|
118
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
119
|
+
React.createElement("span", { className: "font-system text-sm" }, "Type"),
|
|
120
|
+
React.createElement(ListBox, { label: "Type", value: pattern, items: dateTimeTypes.map((p) => ({
|
|
121
|
+
value: p,
|
|
122
|
+
label: render(p, sampleDate()),
|
|
123
|
+
})), onChange: (p) => onChange({
|
|
124
|
+
type: category === "date" ? "DATE" : "DATE_TIME",
|
|
125
|
+
pattern: p,
|
|
126
|
+
}) })),
|
|
127
|
+
localeField));
|
|
128
|
+
break;
|
|
129
|
+
case "fraction":
|
|
130
|
+
options = (React.createElement("div", { className: "flex flex-col gap-1" },
|
|
131
|
+
React.createElement("span", { className: "font-system text-sm" }, "Type"),
|
|
132
|
+
React.createElement(ListBox, { label: "Type", value: pattern, items: FRACTION_TYPES.map((t) => ({ value: t.pattern, label: t.label })), onChange: (p) => onChange({ type: "FRACTION", pattern: p }) })));
|
|
133
|
+
break;
|
|
134
|
+
case "special":
|
|
135
|
+
options = (React.createElement(React.Fragment, null,
|
|
136
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
137
|
+
React.createElement("span", { className: "font-system text-sm" }, "Type"),
|
|
138
|
+
React.createElement(ListBox, { label: "Type", value: pattern, items: SPECIAL_TYPES.map((t) => ({ value: t.pattern, label: t.label })), onChange: (p) => onChange({ type: "SPECIAL", pattern: p }) })),
|
|
139
|
+
React.createElement(SelectField, { label: "Locale (location)", value: "en-US", options: [{ value: "en-US", label: "English (United States)" }], onChange: () => undefined })));
|
|
140
|
+
break;
|
|
141
|
+
case "custom":
|
|
142
|
+
options = (React.createElement("div", { className: "flex flex-col gap-1" },
|
|
143
|
+
React.createElement("label", { className: "flex flex-col gap-1 font-system text-sm" },
|
|
144
|
+
"Type",
|
|
145
|
+
React.createElement(Input, { "aria-label": "Custom format code", type: "text", className: "text-xs", value: pattern, onChange: (event) => onChange({
|
|
146
|
+
type: inferTypeFromPattern(event.target.value),
|
|
147
|
+
pattern: event.target.value,
|
|
148
|
+
}) })),
|
|
149
|
+
React.createElement(ListBox, { label: "Custom formats", value: pattern, items: CUSTOM_PATTERNS.map((p) => ({ value: p, label: p })), onChange: (p) => onChange(p === "General" ? null : { type: inferTypeFromPattern(p), pattern: p }) })));
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
return (React.createElement("div", { className: "grid grid-cols-[140px_1fr] gap-3" },
|
|
153
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
154
|
+
React.createElement("span", { className: "font-system text-sm" }, "Category"),
|
|
155
|
+
React.createElement(ListBox, { label: "Category", value: category, items: NUMBER_CATEGORIES.map((c) => ({ value: c.id, label: c.name })), onChange: pickCategory, className: "max-h-[260px]" })),
|
|
156
|
+
React.createElement("div", { className: "flex flex-col gap-2" },
|
|
157
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
158
|
+
React.createElement("span", { className: "font-system text-sm" }, "Sample"),
|
|
159
|
+
React.createElement("div", { "data-testid": "number-sample", className: "rounded-sm bg-rnc-muted p-1 px-2 text-rnc-foreground", style: { color: colorOf(pattern, sampleValue) } }, sample)),
|
|
160
|
+
options,
|
|
161
|
+
React.createElement("p", { className: "font-system text-xs text-rnc-muted-foreground" }, definition?.description))));
|
|
162
|
+
};
|
|
163
|
+
// Excel previews date and time types on the active cell's value when it is a
|
|
164
|
+
// date; a fixed date keeps the list stable otherwise.
|
|
165
|
+
const sampleDate = () => new Date(2012, 2, 14, 13, 30, 55);
|