From 23cb01e3187d38617ce2d0a92d84c94bf98c0e4d Mon Sep 17 00:00:00 2001
From: SheetJS <dev@sheetjs.com>
Date: Thu, 18 May 2023 05:21:08 -0400
Subject: [PATCH] nf

---
 docz/docs/07-csf/02-cell.md                   |   2 +-
 docz/docs/07-csf/07-features/05-names.md      |   2 +-
 docz/docs/07-csf/07-features/06-nf.md         | 218 ++++++++++++++++++
 docz/docs/07-csf/07-features/index.md         |  76 ------
 ...5-parse-options.md => 03-parse-options.md} |   2 +-
 ...7-write-options.md => 05-write-options.md} |   2 +-
 .../09-formulae.md                            |   2 +-
 .../_category_.json                           |   2 +-
 .../{09-utilities => 07-utilities}/index.md   |   2 +-
 9 files changed, 225 insertions(+), 83 deletions(-)
 create mode 100644 docz/docs/07-csf/07-features/06-nf.md
 rename docz/docs/08-api/{05-parse-options.md => 03-parse-options.md} (99%)
 rename docz/docs/08-api/{07-write-options.md => 05-write-options.md} (99%)
 rename docz/docs/08-api/{09-utilities => 07-utilities}/09-formulae.md (99%)
 rename docz/docs/08-api/{09-utilities => 07-utilities}/_category_.json (78%)
 rename docz/docs/08-api/{09-utilities => 07-utilities}/index.md (99%)

diff --git a/docz/docs/07-csf/02-cell.md b/docz/docs/07-csf/02-cell.md
index 82501d7..39ad55f 100644
--- a/docz/docs/07-csf/02-cell.md
+++ b/docz/docs/07-csf/02-cell.md
@@ -11,7 +11,7 @@ Cell objects are plain JS objects with keys and values following the convention:
 |     | **Core Cell Properties** ([More Info](#data-types))                    |
 | `v` | raw value (number, string, Date object, boolean)                       |
 | `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
-|     | **Number Formats** ([More Info](/docs/csf/features#number-formats))    |
+|     | **Number Formats** ([More Info](/docs/csf/features/nf))                |
 | `z` | number format string associated with the cell (if requested)           |
 | `w` | formatted text (if applicable)                                         |
 |     | **Formulae** ([More Info](/docs/csf/features/formulae))                |
diff --git a/docz/docs/07-csf/07-features/05-names.md b/docz/docs/07-csf/07-features/05-names.md
index 78fcfef..034ba4a 100644
--- a/docz/docs/07-csf/07-features/05-names.md
+++ b/docz/docs/07-csf/07-features/05-names.md
@@ -10,7 +10,7 @@ sidebar_position: 5
 Defined names have evolved over the decades, with new features added over time:
 
 - "English" refers to defined names with English letters and numbers (ASCII)
-- "Unicode" refers to defined names that non-English characters.
+- "Unicode" refers to defined names with non-English characters.
 - "Comment" refers to comments that can be attached to defined names.
 
 | Formats           | English | Unicode | Comment |
diff --git a/docz/docs/07-csf/07-features/06-nf.md b/docz/docs/07-csf/07-features/06-nf.md
new file mode 100644
index 0000000..162b870
--- /dev/null
+++ b/docz/docs/07-csf/07-features/06-nf.md
@@ -0,0 +1,218 @@
+---
+sidebar_position: 6
+---
+
+# Number Formats
+
+<details>
+  <summary><b>File Format Support</b> (click to show)</summary>
+
+Legacy formats like CSV mix "content" and "presentation". There is no true
+concept of a "number format" distinct from the number itself. For specific
+formats, the library will guess the number format.
+
+| Formats           | Basic | Storage Representation |
+|:------------------|:-----:|:-----------------------|
+| XLSX / XLSM       |   ✔   | Number Format Code     |
+| XLSB              |   ✔   | Number Format Code     |
+| XLS               |   ✔   | Number Format Code     |
+| XLML              |   ✔   | Number Format Code     |
+| SYLK              |   R   | Number Format Code     |
+| ODS / FODS / UOS  |   ✔   | XML                    |
+| NUMBERS           |       | Binary encoding        |
+| WK\*              |       | Binary encoding        |
+| WQ\* / WB\* / QPW |       | Binary encoding        |
+| DBF               |       | Implied by field types |
+| CSV               |   *   | N/A                    |
+| PRN               |   *   | N/A                    |
+| DIF               |   *   | N/A                    |
+| RTF               |   *   | N/A                    |
+
+Asterisks (*) mark formats that mix content and presentation. Synthetic number
+formats may be generated for special values.
+
+The letter R (R) marks features parsed but not written in the format.
+
+</details>
+
+The following example generates a file with some common number formats:
+
+```jsx live
+function SheetJSSimpleNF(props) {
+  const xport = React.useCallback(async () => {
+    /* Create worksheet from simple data */
+    const ws = XLSX.utils.aoa_to_sheet([
+      ["Currency", 3.5],
+      ["Thousands", 7262],
+      ["Percent", 0.0219]
+    ]);
+    /* assign number formats */
+    ws["B1"].z = '"$"#,##0_);\\("$"#,##0\\)';
+    ws["B2"].z = '#,##0';
+    ws["B3"].z = "0.00%";
+
+    /* Export to file (start a download) */
+    const wb = XLSX.utils.book_new();
+    XLSX.utils.book_append_sheet(wb, ws, "Formats");
+    XLSX.writeFile(wb, "SheetJSSimpleNF.xlsx");
+  });
+
+  return ( <button onClick={xport}><b>Export XLSX!</b></button> );
+}
+```
+
+## Values and Formatting
+
+Typically spreadsheets will include formatted text such as currencies (`$3.50`)
+or large numbers with thousands separators (`7,262`) or percentages (`2.19%`).
+
+To simplify editing, the applications will store the underlying values and the
+number formats separately. For example, `$3.50` will be represented as the value
+`3.5` with a number format that mandates a `$` sigil and 2 decimal places.
+
+Some file formats like CSV only support the formatted text. Native formats for
+spreadsheet applications including Lotus 1-2-3 and Excel will store the value
+and number format separately.
+
+### Dates and Times
+
+Many spreadsheet formats store dates and times using a number that represents
+the number of seconds or days after some epoch. Dates are covered in more detail
+[in the dedicated section](/docs/csf/features/dates).
+
+## SheetJS Representation
+
+Number formats and values are attached to cells. The following keys are used:
+
+| Key | Description                                                            |
+| --- | ---------------------------------------------------------------------- |
+| `v` | raw value (number, string, Date object, boolean)                       |
+| `z` | number format string associated with the cell (if requested)           |
+| `w` | formatted text (if applicable)                                         |
+
+The `cell.w` formatted text for each cell is produced from `cell.v` and `cell.z`
+format.  If the format is not specified, the Excel `General` format is used.
+
+By default, parsers do not attach number formats to cells.  The `cellNF` option
+instructs `XLSX.read` or `XLSX.readFile` to save the formats.
+
+### Number Format Strings
+
+The `z` format string follows the Excel persistence rules as described in
+ECMA-376 18.8.31 (Number Formats). For more info, see the Excel documentation
+article `Create or delete a custom number format`
+
+The rules are slightly different from how Excel displays custom number formats.
+In particular, literal characters must be wrapped in double quotes or preceded
+by a backslash.
+
+The following example prints number formats from a user-specified file:
+
+```jsx live
+function SheetJSExtractNF(props) {
+  const [rows, setRows] = React.useState([])
+
+  return ( <>
+    <input type="file" onChange={async(e) => {
+      /* parse workbook with cellNF: true */
+      const file = e.target.files[0];
+      const data = await file.arrayBuffer();
+      const wb = XLSX.read(data, {cellNF: true});
+
+      const formats = {};
+      wb.SheetNames.forEach(n => {
+        var ws = wb.Sheets[n]; if(!ws || !ws["!ref"]) return;
+        var ref = XLSX.utils.decode_range(ws["!ref"]);
+        for(var R = 0; R <= ref.e.r; ++R) for(var C = 0; C <= ref.e.c; ++C) {
+          var addr = XLSX.utils.encode_cell({r:R,c:C});
+          if(!ws[addr] || !ws[addr].z) continue;
+          if(formats[ws[addr].z]) continue;
+          formats[ws[addr].z] = `'${n}'!${addr}`;
+          setRows(Object.entries(formats));
+        }
+      });
+    }}/>
+    <table><tr><th>Format</th><th>JSON</th><th>Example Cell</th></tr>
+    {rows.map((r,R) => ( <tr key={R}>
+      <td><code>{r[0]}</code></td>
+      <td><code>{JSON.stringify(r[0])}</code></td>
+      <td>{r[1]}</td>
+    </tr> ))}
+    </table>
+  </> );
+}
+```
+
+## Miscellany
+
+The default formats are listed in ECMA-376 18.8.30:
+
+<details>
+  <summary><b>Default Number Formats</b> (click to show)</summary>
+
+| ID | Format                     |
+|---:|:---------------------------|
+|  0 | `General`                  |
+|  1 | `0`                        |
+|  2 | `0.00`                     |
+|  3 | `#,##0`                    |
+|  4 | `#,##0.00`                 |
+|  9 | `0%`                       |
+| 10 | `0.00%`                    |
+| 11 | `0.00E+00`                 |
+| 12 | `# ?/?`                    |
+| 13 | `# ??/??`                  |
+| 14 | `m/d/yy` (see below)       |
+| 15 | `d-mmm-yy`                 |
+| 16 | `d-mmm`                    |
+| 17 | `mmm-yy`                   |
+| 18 | `h:mm AM/PM`               |
+| 19 | `h:mm:ss AM/PM`            |
+| 20 | `h:mm`                     |
+| 21 | `h:mm:ss`                  |
+| 22 | `m/d/yy h:mm`              |
+| 37 | `#,##0 ;(#,##0)`           |
+| 38 | `#,##0 ;[Red](#,##0)`      |
+| 39 | `#,##0.00;(#,##0.00)`      |
+| 40 | `#,##0.00;[Red](#,##0.00)` |
+| 45 | `mm:ss`                    |
+| 46 | `[h]:mm:ss`                |
+| 47 | `mmss.0`                   |
+| 48 | `##0.0E+0`                 |
+| 49 | `@`                        |
+
+</details>
+
+Format 14 (`m/d/yy`) is localized by Excel: even though the file specifies that
+number format, it will be drawn differently based on system settings.  It makes
+sense when the producer and consumer of files are in the same locale, but that
+is not always the case over the Internet.  To get around this ambiguity, parse
+functions accept the `dateNF` option to override the interpretation of that
+specific format string.
+
+### Excel Format Categories
+
+Excel officially recognizes a small number of formats as "Currency" and another
+set of formats as "Accounting".  The exact formats in `en-US` are listed below:
+
+#### Currency
+
+| JS String                                | Decimal Places | Negative Color |
+|:-----------------------------------------|:---------------|:---------------|
+| `'"$"#,##0_);\\("$"#,##0\\)'`            | 0              | Black          |
+| `'"$"#,##0_);[Red]\\("$"#,##0\\)'`       | 0              | Red            |
+| `'"$"#,##0.00_);\\("$"#,##0.00\\)'`      | 2              | Black          |
+| `'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)'` | 2              | Red            |
+
+#### Accounting
+
+| JS String                                                        | Decimal | Sigil |
+|:-----------------------------------------------------------------|:--------|:------|
+| `'_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)'`                  | 0       |       |
+| `'_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)'`         | 0       | `$`   |
+| `'_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)'`          | 2       |       |
+| `'_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'` | 2       | `$`   |
+
+For other locales, the formats can be discovered by creating a file with the
+desired format and testing with [the Number Format Strings demo](#number-format-strings)
+
diff --git a/docz/docs/07-csf/07-features/index.md b/docz/docs/07-csf/07-features/index.md
index 94fffd2..8bc91d9 100644
--- a/docz/docs/07-csf/07-features/index.md
+++ b/docz/docs/07-csf/07-features/index.md
@@ -138,82 +138,6 @@ follow the priority order:
 
 </details>
 
-## Number Formats
-
-The `cell.w` formatted text for each cell is produced from `cell.v` and `cell.z`
-format.  If the format is not specified, the Excel `General` format is used.
-The format can either be specified as a string or as an index into the format
-table.  Readers are expected to populate `workbook.SSF` with the number format
-table.  Writers are expected to serialize the table.
-
-The following example creates a custom format from scratch:
-
-```js
-var wb = {
-  SheetNames: ["Sheet1"],
-  Sheets: {
-    Sheet1: {
-      "!ref":"A1:C1",
-      A1: { t:"n", v:10000 },                    // <-- General format
-      B1: { t:"n", v:10000, z: "0%" },           // <-- Builtin format
-      C1: { t:"n", v:10000, z: "\"T\"\ #0.00" }  // <-- Custom format
-    }
-  }
-}
-```
-
-The rules are slightly different from how Excel displays custom number formats.
-In particular, literal characters must be wrapped in double quotes or preceded
-by a backslash. For more info, see the Excel documentation article
-`Create or delete a custom number format` or ECMA-376 18.8.31 (Number Formats)
-
-
-<details>
-  <summary><b>Default Number Formats</b> (click to show)</summary>
-
-The default formats are listed in ECMA-376 18.8.30:
-
-| ID | Format                     |
-|---:|:---------------------------|
-|  0 | `General`                  |
-|  1 | `0`                        |
-|  2 | `0.00`                     |
-|  3 | `#,##0`                    |
-|  4 | `#,##0.00`                 |
-|  9 | `0%`                       |
-| 10 | `0.00%`                    |
-| 11 | `0.00E+00`                 |
-| 12 | `# ?/?`                    |
-| 13 | `# ??/??`                  |
-| 14 | `m/d/yy` (see below)       |
-| 15 | `d-mmm-yy`                 |
-| 16 | `d-mmm`                    |
-| 17 | `mmm-yy`                   |
-| 18 | `h:mm AM/PM`               |
-| 19 | `h:mm:ss AM/PM`            |
-| 20 | `h:mm`                     |
-| 21 | `h:mm:ss`                  |
-| 22 | `m/d/yy h:mm`              |
-| 37 | `#,##0 ;(#,##0)`           |
-| 38 | `#,##0 ;[Red](#,##0)`      |
-| 39 | `#,##0.00;(#,##0.00)`      |
-| 40 | `#,##0.00;[Red](#,##0.00)` |
-| 45 | `mm:ss`                    |
-| 46 | `[h]:mm:ss`                |
-| 47 | `mmss.0`                   |
-| 48 | `##0.0E+0`                 |
-| 49 | `@`                        |
-
-</details>
-
-Format 14 (`m/d/yy`) is localized by Excel: even though the file specifies that
-number format, it will be drawn differently based on system settings.  It makes
-sense when the producer and consumer of files are in the same locale, but that
-is not always the case over the Internet.  To get around this ambiguity, parse
-functions accept the `dateNF` option to override the interpretation of that
-specific format string.
-
-
 ## Sheet Visibility
 
 <details>
diff --git a/docz/docs/08-api/05-parse-options.md b/docz/docs/08-api/03-parse-options.md
similarity index 99%
rename from docz/docs/08-api/05-parse-options.md
rename to docz/docs/08-api/03-parse-options.md
index 57b3fe5..3935894 100644
--- a/docz/docs/08-api/05-parse-options.md
+++ b/docz/docs/08-api/03-parse-options.md
@@ -1,5 +1,5 @@
 ---
-sidebar_position: 5
+sidebar_position: 3
 hide_table_of_contents: true
 title: Reading Files
 ---
diff --git a/docz/docs/08-api/07-write-options.md b/docz/docs/08-api/05-write-options.md
similarity index 99%
rename from docz/docs/08-api/07-write-options.md
rename to docz/docs/08-api/05-write-options.md
index fd8e64a..fcecb23 100644
--- a/docz/docs/08-api/07-write-options.md
+++ b/docz/docs/08-api/05-write-options.md
@@ -1,5 +1,5 @@
 ---
-sidebar_position: 7
+sidebar_position: 5
 hide_table_of_contents: true
 title: Writing Files
 ---
diff --git a/docz/docs/08-api/09-utilities/09-formulae.md b/docz/docs/08-api/07-utilities/09-formulae.md
similarity index 99%
rename from docz/docs/08-api/09-utilities/09-formulae.md
rename to docz/docs/08-api/07-utilities/09-formulae.md
index 6fa2e18..71e6183 100644
--- a/docz/docs/08-api/09-utilities/09-formulae.md
+++ b/docz/docs/08-api/07-utilities/09-formulae.md
@@ -1,6 +1,6 @@
 ---
 sidebar_position: 9
-title: Formulae Output
+title: Array of Formulae
 pagination_next: miscellany/formats
 ---
 
diff --git a/docz/docs/08-api/09-utilities/_category_.json b/docz/docs/08-api/07-utilities/_category_.json
similarity index 78%
rename from docz/docs/08-api/09-utilities/_category_.json
rename to docz/docs/08-api/07-utilities/_category_.json
index 6d797b3..b747ff8 100644
--- a/docz/docs/08-api/09-utilities/_category_.json
+++ b/docz/docs/08-api/07-utilities/_category_.json
@@ -1,5 +1,5 @@
 {
   "label": "Utility Functions",
   "collapsed": false,
-  "position": 9
+  "position": 7
 }
diff --git a/docz/docs/08-api/09-utilities/index.md b/docz/docs/08-api/07-utilities/index.md
similarity index 99%
rename from docz/docs/08-api/09-utilities/index.md
rename to docz/docs/08-api/07-utilities/index.md
index ecf35bd..a19fff0 100644
--- a/docz/docs/08-api/09-utilities/index.md
+++ b/docz/docs/08-api/07-utilities/index.md
@@ -440,7 +440,7 @@ can be added to the individual TD elements:
 |:----------|:-------------------------------------------------------------|
 | `data-t`  | Override [Cell Type](/docs/csf/cell#data-types)              |
 | `data-v`  | Override Cell Value                                          |
-| `data-z`  | Override [Number Format](/docs/csf/features/#number-formats) |
+| `data-z`  | Override [Number Format](/docs/csf/features/nf)              |
 
 For example: