@nxgt/material 3.75.0 → 3.76.0
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/CHANGELOG.md +40 -0
- package/README.md +37 -1
- package/dist/{alert-dialog-BfO_ri-N.js → alert-dialog-653apk3f.js} +8 -7
- package/dist/{async-slice-roMAJVzG.js → async-slice-CXLbQuOc.js} +1 -1
- package/dist/{bubble-input-B7BVd9fX.js → bubble-input-CQwVSoU3.js} +30 -29
- package/dist/{button-DgenqmpS.js → button-3op3rtZh.js} +5 -4
- package/dist/calculator-BaSMe0SK.js +1189 -0
- package/dist/calculator-announce-DRd2c6Dq.js +89 -0
- package/dist/calculator-context-BugcKuVG.js +10 -0
- package/dist/calculator-field.js +172 -0
- package/dist/calculator-panel-announce-AZSnZUSr.js +29 -0
- package/dist/calculator-segment-BlJE1LaS.js +22 -0
- package/dist/calculator.js +2 -0
- package/dist/charts.js +3 -3
- package/dist/{chip-CiDczNxO.js → chip-MuKDwtkG.js} +2 -2
- package/dist/{code-editor-CohlhFsA.js → code-editor-Bp2RrdNx.js} +13 -13
- package/dist/code-editor.js +37 -37
- package/dist/{code-language-items-Cs8GLYDp.js → code-language-items-B7WR5ua_.js} +19 -24
- package/dist/components/base-content.css +9 -4
- package/dist/components/ui/collections/server-table/server-table-phone-row.css +10 -3
- package/dist/{components-zJdfH4im.js → components-Ci3Zo8kC.js} +15837 -17245
- package/dist/components.js +37 -28
- package/dist/conversion-variant-BDFAxqe9.js +529 -0
- package/dist/copy-to-clipboard-Be5Ffvs_.js +7 -0
- package/dist/currency-B-r3ig11.js +16 -0
- package/dist/currency-field-BJ9rSrif.js +285 -0
- package/dist/{number.utils-BG_eEt5g.js → date.utils-DUvqcjan.js} +1 -7
- package/dist/dialog-Bm5LvVlB.js +166 -0
- package/dist/dist-BZe2evxL.js +139 -0
- package/dist/dist-CxhKjOYm.js +28 -0
- package/dist/dist-DHdUUM1w.js +241 -0
- package/dist/{dist-C4wtXCjf.js → dist-DOK3zo5C.js} +33 -32
- package/dist/dist-DWZXlCZR.js +182 -0
- package/dist/dist-DkQbkF9T.js +33 -0
- package/dist/dnd.js +1 -1
- package/dist/{dropdown-menu-CzR6JP31.js → dropdown-menu-xlZ6NYUA.js} +160 -159
- package/dist/editor.js +299 -298
- package/dist/{empty-state-DjHGMp5F.js → empty-state-C0kviQdW.js} +2 -2
- package/dist/{field-blur-CdASxjL7.js → field-blur-DkiZOVNV.js} +178 -180
- package/dist/{field-blur-context-kZ4SD7xu.js → field-blur-context-BLGgf_3z.js} +2 -2
- package/dist/financial-variant-BsZEa5sF.js +459 -0
- package/dist/{hooks-Dqq8O3Az.js → hooks-Dg94jPRq.js} +12 -12
- package/dist/hooks.js +2 -2
- package/dist/{hover-card-BPKqte4a.js → hover-card-B1g55Hi6.js} +44 -43
- package/dist/i18n.js +3 -3
- package/dist/icon-badge-BcW66bRk.js +17 -0
- package/dist/{icon-button-Cr-DyDGg.js → icon-button-Cogxy1cy.js} +5 -4
- package/dist/{in-dialog-Vwkyp-M5.js → in-dialog-D61Yeaol.js} +2 -1
- package/dist/input-CC2joTjB.js +56 -0
- package/dist/key-layout-cR79xfGE.js +38 -0
- package/dist/lib/calculator/index.d.ts +16 -0
- package/dist/lib/calculator-field/index.d.ts +12 -0
- package/dist/lib/components/ui/collections/filter/use-filter-field-config.d.ts +2 -2
- package/dist/lib/components/ui/feedback/moment/moment-body.d.ts +17 -2
- package/dist/lib/components/ui/feedback/moment/moment-passive.d.ts +13 -0
- package/dist/lib/components/ui/feedback/moment/moment.d.ts +16 -2
- package/dist/lib/components/ui/fields/calculator-field/apply-calculated.d.ts +17 -0
- package/dist/lib/components/ui/fields/calculator-field/calculator-field-content.d.ts +16 -0
- package/dist/lib/components/ui/fields/calculator-field/calculator-field-trigger.d.ts +4 -0
- package/dist/lib/components/ui/fields/calculator-field/calculator-field.d.ts +12 -0
- package/dist/lib/components/ui/fields/calculator-field/calculator-field.types.d.ts +31 -0
- package/dist/lib/components/ui/fields/calculator-field/calculator-form-field.d.ts +4 -0
- package/dist/lib/components/ui/fields/calculator-field/index.d.ts +3 -0
- package/dist/lib/components/ui/fields/calculator-field/use-calculator-field.d.ts +15 -0
- package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
- package/dist/lib/components/ui/fields/currency-field/currency-field.d.ts +7 -1
- package/dist/lib/components/ui/layout/app-shell/app-sidebar-context.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/calculator-announce.d.ts +27 -0
- package/dist/lib/components/ui/widgets/calculator/calculator-clipboard.d.ts +19 -0
- package/dist/lib/components/ui/widgets/calculator/calculator-context.d.ts +49 -0
- package/dist/lib/components/ui/widgets/calculator/calculator-feedback.d.ts +18 -0
- package/dist/lib/components/ui/widgets/calculator/calculator-keyboard.d.ts +30 -0
- package/dist/lib/components/ui/widgets/calculator/calculator-storage.d.ts +17 -0
- package/dist/lib/components/ui/widgets/calculator/calculator-variant-steps.d.ts +16 -0
- package/dist/lib/components/ui/widgets/calculator/calculator.d.ts +11 -0
- package/dist/lib/components/ui/widgets/calculator/calculator.selectors.d.ts +23 -0
- package/dist/lib/components/ui/widgets/calculator/calculator.slice.d.ts +1881 -0
- package/dist/lib/components/ui/widgets/calculator/currency.d.ts +9 -0
- package/dist/lib/components/ui/widgets/calculator/engine.d.ts +22 -0
- package/dist/lib/components/ui/widgets/calculator/index.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-announcer.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-display.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-key.d.ts +17 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-keypad.d.ts +8 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-loading.d.ts +6 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-memory.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-panel-announce.d.ts +10 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-panel-body.d.ts +9 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-screen.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-segment.d.ts +21 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-shell.d.ts +9 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-switcher.d.ts +5 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-tape.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/partials/calculator-tools.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/partials/keypad-navigation.d.ts +24 -0
- package/dist/lib/components/ui/widgets/calculator/types.d.ts +102 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-clipboard.d.ts +19 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-conversion.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-feedback.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-keyboard.d.ts +22 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-persistence.d.ts +14 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-pos.d.ts +25 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-press.d.ts +26 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-tape.d.ts +29 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-value.d.ts +9 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator-variant.d.ts +23 -0
- package/dist/lib/components/ui/widgets/calculator/use-calculator.d.ts +10 -0
- package/dist/lib/components/ui/widgets/calculator/use-engine-settings.d.ts +10 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-fields.d.ts +19 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-labels.d.ts +17 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-math.d.ts +31 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-names.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-panel.d.ts +7 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-rates.d.ts +29 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-result.d.ts +15 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-state.d.ts +36 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/conversion-variant.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/variants/conversion/use-conversion.d.ts +24 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-change.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-figures.d.ts +43 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-format.d.ts +12 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-loan-math.d.ts +14 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-loan.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-margin.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-math.d.ts +10 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-panel.d.ts +7 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-parts.d.ts +35 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-table.d.ts +7 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-variant.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/variants/financial/financial-vat.d.ts +4 -0
- package/dist/lib/components/ui/widgets/calculator/variants/key-layout.d.ts +51 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-announce.d.ts +16 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-aside.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-display.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-fields.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-layout.d.ts +9 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-line.d.ts +6 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-names.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-state.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-tender.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-ticket-data.d.ts +41 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-ticket.d.ts +5 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-totals.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-types.d.ts +76 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-variant.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-vat.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/pos/pos-view.d.ts +28 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-announce.d.ts +19 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-base.d.ts +11 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-bitpad.d.ts +14 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-display.d.ts +9 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-layout.d.ts +6 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-names.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-readouts.d.ts +14 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-reduce.d.ts +29 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-state.d.ts +22 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-toolbar.d.ts +5 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-variant.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/variants/programmer/programmer-word.d.ts +15 -0
- package/dist/lib/components/ui/widgets/calculator/variants/registry.d.ts +21 -0
- package/dist/lib/components/ui/widgets/calculator/variants/scientific/scientific-layout.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/variants/scientific/scientific-names.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/scientific/scientific-toolbar.d.ts +2 -0
- package/dist/lib/components/ui/widgets/calculator/variants/scientific/scientific-variant.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/variants/standard/standard-layout.d.ts +3 -0
- package/dist/lib/components/ui/widgets/calculator/variants/variant-loader.d.ts +34 -0
- package/dist/lib/components/ui/widgets/calculator/variants/variant-logic.d.ts +40 -0
- package/dist/lib/components/ui/widgets/calculator/variants/variant-types.d.ts +62 -0
- package/dist/lib/i18n/resources/en/en.d.ts +412 -0
- package/dist/lib/i18n/resources/en/material.json.d.ts +412 -0
- package/dist/lib/i18n/resources/fr/fr.d.ts +412 -0
- package/dist/lib/i18n/resources/fr/material.json.d.ts +412 -0
- package/dist/lib/i18n/resources/resources.d.ts +824 -0
- package/dist/lib/i18n/translator.d.ts +1 -1
- package/dist/lib.js +4 -3
- package/dist/main.js +50 -40
- package/dist/map.js +66 -65
- package/dist/material.css +1 -1
- package/dist/native-select-w_FlBLHV.js +40 -0
- package/dist/number.utils-CSueQZcv.js +7 -0
- package/dist/pdf-reader.js +1 -1
- package/dist/percent-field-lahyDJDG.js +14 -0
- package/dist/picker-surface-CV09H7Nb.js +1220 -0
- package/dist/popover-Cd7DkND4.js +233 -0
- package/dist/pos-types-DKCkOTYy.js +49 -0
- package/dist/pos-variant-GrUfbTTP.js +603 -0
- package/dist/print.js +1 -1
- package/dist/programmer-variant-eKJNKENL.js +501 -0
- package/dist/programmer-word-CNCF7DJF.js +15 -0
- package/dist/{public-DC9VQw4Z.js → public-y6g4ddxd.js} +895 -892
- package/dist/{rich-code-block-DBSL9zEN.js → rich-code-block-CRQ0iyLb.js} +5 -5
- package/dist/scientific-variant-2y3UxAAU.js +149 -0
- package/dist/{sortable-provider-C4tk5esY.js → sortable-provider-DdiI3Fwk.js} +2 -2
- package/dist/{spinner-B2MubVWb.js → spinner-C1QIewWv.js} +133 -159
- package/dist/standard-layout-BuSRr3TY.js +40 -0
- package/dist/tabs-DzEqMb1W.js +383 -0
- package/dist/{icon-badge-B9uvDoyY.js → text-field-BAdY-kpO.js} +20 -34
- package/dist/theme-picker.js +3 -3
- package/dist/{theme-toggle-BInlu21G.js → theme-toggle-C_VeiiCm.js} +2 -2
- package/dist/toggle-FeCCJqbg.js +40 -0
- package/dist/{toggle-group-DXXlqid2.js → toggle-group-CVMxEpWi.js} +1 -1
- package/dist/{toolbar-items-CRJSx1MU.js → toolbar-items-D310xDuM.js} +333 -554
- package/dist/{translate-material-pVlPJ1v4.js → translate-material-BypJJ1l5.js} +1 -1
- package/dist/{translator-BoYCward.js → translator-DJkf4J7t.js} +824 -0
- package/dist/{typography-B6YMbCge.js → typography-CYEquVeb.js} +1 -1
- package/dist/{use-chat-composer-BvWQogJe.js → use-chat-composer-DMXu9E1O.js} +4198 -4600
- package/dist/{use-heading-spy-B_Z4ArDh.js → use-heading-spy-DJR8YYm6.js} +19 -19
- package/dist/{use-material-translation-CIS2n3RB.js → use-material-translation-CD6QoVal.js} +1 -1
- package/dist/{use-return-focus-DNQtADAR.js → use-return-focus-Cevw_6yq.js} +106 -105
- package/dist/useLatest-C2PnQEeD.js +8 -0
- package/docs/README.md +1 -0
- package/docs/components/feedback-and-status.md +10 -1
- package/docs/components/form-fields.md +1 -0
- package/docs/components/rich-widgets.md +108 -0
- package/docs/getting-started.md +1 -0
- package/docs/guides/calculator.md +468 -0
- package/docs/guides/forms.md +4 -2
- package/docs/guides/i18n.md +5 -0
- package/docs/previews/rich-widgets-calculator-conversion.webp +0 -0
- package/docs/previews/rich-widgets-calculator-point-of-sale.webp +0 -0
- package/docs/previews/rich-widgets-calculator.webp +0 -0
- package/docs/roadmap.md +9 -3
- package/docs/troubleshooting.md +134 -0
- package/lib/components/base-content.css +9 -4
- package/lib/components/ui/collections/server-table/server-table-phone-row.css +10 -3
- package/lib/components/ui/widgets/calculator/calculator-bands.css +146 -0
- package/lib/components/ui/widgets/calculator/calculator-display.css +83 -0
- package/lib/components/ui/widgets/calculator/calculator-keys.css +118 -0
- package/lib/components/ui/widgets/calculator/calculator-pos-ticket.css +185 -0
- package/lib/components/ui/widgets/calculator/calculator-pos.css +38 -0
- package/lib/components/ui/widgets/calculator/calculator-tape.css +71 -0
- package/lib/components/ui/widgets/calculator/calculator.css +97 -0
- package/lib/components/ui/widgets/calculator/variants/conversion/conversion.css +98 -0
- package/lib/components/ui/widgets/calculator/variants/financial/financial.css +162 -0
- package/lib/components/ui/widgets/calculator/variants/programmer/programmer.css +162 -0
- package/package.json +17 -3
- package/dist/dialog-AGsB3bv4.js +0 -219
- package/dist/dist-B7RjY7SL.js +0 -158
- package/dist/dist-lmHmz_bu.js +0 -419
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
# Calculator
|
|
2
|
+
|
|
3
|
+
`@nxgt/material/calculator` is a calculator for your app: exact decimal
|
|
4
|
+
arithmetic (`0.1 + 0.2` is `0.3`), the usual precedence (`2 + 3 × 4` is `14`),
|
|
5
|
+
the whole expression shown above the result, a tape of past results, a memory,
|
|
6
|
+
the physical keyboard, copy and paste, and a screen-reader announcement of each
|
|
7
|
+
result. Standard, Scientific, the point of sale, Financial, Conversion and
|
|
8
|
+
Programmer ship.
|
|
9
|
+
|
|
10
|
+
The maths is `@nxgt/material-core/calculator`: a decimal engine on `BigInt`
|
|
11
|
+
with its own expression parser, so nothing is evaluated as code and a strict
|
|
12
|
+
Content Security Policy is satisfied. The component is a thin shell over it.
|
|
13
|
+
|
|
14
|
+
- [Set up](#set-up)
|
|
15
|
+
- [The Standard calculator](#the-standard-calculator)
|
|
16
|
+
- [The Scientific calculator](#the-scientific-calculator)
|
|
17
|
+
- [The point-of-sale calculator](#the-point-of-sale-calculator)
|
|
18
|
+
- [The Financial calculator](#the-financial-calculator)
|
|
19
|
+
- [The conversion calculator](#the-conversion-calculator)
|
|
20
|
+
- [The Programmer calculator](#the-programmer-calculator)
|
|
21
|
+
- [Props](#props)
|
|
22
|
+
- [Keyboard](#keyboard)
|
|
23
|
+
- [Tape and memory](#tape-and-memory)
|
|
24
|
+
- [Copy and paste](#copy-and-paste)
|
|
25
|
+
- [What is stored](#what-is-stored)
|
|
26
|
+
- [Feedback](#feedback)
|
|
27
|
+
- [Sizing](#sizing)
|
|
28
|
+
- [Accessibility](#accessibility)
|
|
29
|
+
- [Translations](#translations)
|
|
30
|
+
- [Troubleshooting](#troubleshooting)
|
|
31
|
+
|
|
32
|
+
## Set up
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { Calculator } from '@nxgt/material/calculator';
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The entry is its own: it is not in `@nxgt/material` or
|
|
39
|
+
`@nxgt/material/components`. Its stylesheet is opt-in too: `styles.css` does
|
|
40
|
+
not carry it, so import `@nxgt/material/calculator.css` once, after
|
|
41
|
+
`styles.css` (also for `CalculatorField`, which opens the calculator):
|
|
42
|
+
|
|
43
|
+
```css
|
|
44
|
+
@import "@nxgt/material/styles.css";
|
|
45
|
+
@import "@nxgt/material/calculator.css";
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
(or `import '@nxgt/material/calculator.css'` in your entry module). Colours and
|
|
49
|
+
tokens still come from `styles.css`, which your app already imports. It renders on the server; the tape and memory
|
|
50
|
+
are read from `localStorage` after mount, so the first client frame matches the
|
|
51
|
+
server's.
|
|
52
|
+
|
|
53
|
+
## The Standard calculator
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<Calculator />
|
|
57
|
+
<Calculator locale="fr" persist={{ key: 'till-1' }} onResult={(value) => save(value)} />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The display shows the expression above a large result that previews the value
|
|
61
|
+
while you type. The keypad has `( )` and the memory keys on top, then `C`, `±`,
|
|
62
|
+
`%`, `÷ × − +`, the digits, the decimal separator of the locale, `⌫` and `=`, a
|
|
63
|
+
primary pill. `%` follows the `percent` prop below. A result is
|
|
64
|
+
exact; an inexact one (`1 / 3`) is rounded to 34 digits and shown with 16.
|
|
65
|
+
|
|
66
|
+
## Loading
|
|
67
|
+
|
|
68
|
+
Only Standard is in the entry itself. Every other variant, with its engine, is loaded
|
|
69
|
+
on demand the first time it is shown (by `variant`, `defaultVariant` or the switcher,
|
|
70
|
+
which starts the download on hover and focus). Until it arrives the body is a skeleton
|
|
71
|
+
of Standard's size with a polite "Loading the calculator" status
|
|
72
|
+
(`material.calculator.loading`); a download that fails says "This calculator could not
|
|
73
|
+
be loaded." (`material.calculator.load-failed`) and offers "Try again"
|
|
74
|
+
(`material.calculator.retry`), which loads it again. On the server that loading body is what
|
|
75
|
+
renders, then the client hydrates and fetches the variant. The brief loading state the
|
|
76
|
+
first time is expected, and there is no public preload. A browser may keep a failed dynamic
|
|
77
|
+
import until the page reloads, so if Try again fails again, reload the page. Keys
|
|
78
|
+
and paste do nothing while a variant loads. See
|
|
79
|
+
[the troubleshooting entry](../troubleshooting.md#this-calculator-could-not-be-loaded).
|
|
80
|
+
|
|
81
|
+
## The Scientific calculator
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
<Calculator defaultVariant="scientific" />
|
|
85
|
+
<Calculator variants={['scientific']} />
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The switcher shows Standard, Scientific, Point of sale, Financial, Conversion and Programmer; `variants` narrows it (one hides
|
|
89
|
+
it). Scientific calculates with `@nxgt/material-core/calculator/scientific`:
|
|
90
|
+
exact to `precision` digits (34), so `sin(30)` is `0.5`, `cos(90)` is `0` and
|
|
91
|
+
`tan(90)` is an error, never a huge number. It brings a toolbar and a pane of
|
|
92
|
+
functions above the Standard keys on a phone, beside them from 600px to 719px
|
|
93
|
+
and from 1000px up (from 720px to 999px the tape takes its column and the pane
|
|
94
|
+
stays above).
|
|
95
|
+
|
|
96
|
+
| Keys | |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `sin cos tan sinh cosh tanh` | In the toolbar's angle unit; **2nd** turns them into `asin acos atan asinh acosh atanh` (the button stays, so focus stays) |
|
|
99
|
+
| `ln log log₂ 10ˣ eˣ |x|` | `log` is base 10; `10ˣ` is `10^x` for any exponent (`10^2.5` is `316.2277…`) |
|
|
100
|
+
| `x² xʸ √ ʸ√x n! 1/x` | `√`, `ʸ√x` (`nroot(x, y)`), `x²` and `1/x` open a call: type the argument; `=` closes it |
|
|
101
|
+
| `π e EE mod , Ans` | `EE` starts the exponent of the number you are typing, so `3 EE 5` is `3e5` (300000), `± ` after it signs the exponent (`3e-5`) and it does nothing after an operator or `=`; `,` separates the arguments of `ʸ√x` (`nroot(x, y)`), `Ans` is the last result |
|
|
102
|
+
|
|
103
|
+
Toolbar: **DEG RAD GRAD** (a named group of toggle buttons with
|
|
104
|
+
`aria-pressed`; the unit applies to the trigonometric functions and their
|
|
105
|
+
inverses), **2nd** (a toggle with `aria-pressed`, announced "Second functions
|
|
106
|
+
on") and **Auto Sci Eng** (the same kind of group). Auto switches to powers of ten for results from
|
|
107
|
+
16 digits or below 1e-7; Sci writes `1.2345678E+7` and Eng
|
|
108
|
+
`12.345678E+6`, exponent a multiple of 3. Changing the unit or the notation is
|
|
109
|
+
announced ("Angles in radians", "Scientific notation"). `%` is `/100` here
|
|
110
|
+
(`100 + 10%` is `100.1`) unless you set `percent`. The keyboard also types
|
|
111
|
+
`^`, `!`, `p` (π), `r` (√) and `;` between arguments. No graphs and no complex
|
|
112
|
+
numbers: `sqrt(-1)` is "Undefined result".
|
|
113
|
+
|
|
114
|
+
## The point-of-sale calculator
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
<Calculator
|
|
118
|
+
defaultVariant="pos"
|
|
119
|
+
currency="EUR"
|
|
120
|
+
vatRates={[20, 5.5]}
|
|
121
|
+
denominations={[5, 10, 20, 50]}
|
|
122
|
+
onCharge={(total, ticket) => pay(total, ticket)}
|
|
123
|
+
/>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The props below are read only by this variant (`currency` is shared). A point of sale till for a counter, on `@nxgt/material-core/calculator/pos`; the
|
|
127
|
+
tab is named "Point of sale". The keys type an amount the way a till does:
|
|
128
|
+
`1`, `2`, `5` is `1.25`, `00` adds two zeros, backspace drops the last digit,
|
|
129
|
+
`C` clears it. `+` adds it to the ticket. `×` types a quantity first (`2.50 ×
|
|
130
|
+
3 +` is a line of 7.50), `%` types a discount first, as a whole percent or,
|
|
131
|
+
with the **Amount** choice, an amount; a discount typed with no price applies
|
|
132
|
+
to the whole ticket. The chips above the keys (Price, Quantity, Discount,
|
|
133
|
+
Tendered) show what the keys type into.
|
|
134
|
+
|
|
135
|
+
The ticket lists its lines, each removable on its own; on a phone it sits under
|
|
136
|
+
the keys and folds away, from 600px it sits beside them. The totals show the
|
|
137
|
+
subtotal and discount when there is one, the VAT of each rate and the total.
|
|
138
|
+
**Tendered** types what the customer hands over (the `+` key then only
|
|
139
|
+
announces the result); the bills under the ticket are the exact total and up to
|
|
140
|
+
three round amounts from `denominations` (`[5, 10, 20, 50]` for 17.30 gives
|
|
141
|
+
17.30, 20, 50). The line under them is the change, or what is still due, and
|
|
142
|
+
**Charge** is off while the payment is short.
|
|
143
|
+
|
|
144
|
+
| Prop | Default | |
|
|
145
|
+
| --- | --- | --- |
|
|
146
|
+
| `currency` | none | ISO 4217 code (a prop of the calculator, shared by the variants that show amounts): sets the decimals (`JPY` 0, `EUR` 2, `KWD` 3) and is written beside the amounts. None: two decimals and no code |
|
|
147
|
+
| `vatRates` | none | The VAT rates in percent (`[20, '5.5']`); the first is the default, a chip chooses the rate of the next line. None: no VAT |
|
|
148
|
+
| `pricesIncludeVat` | `true` | The prices typed include the VAT; `false`: the VAT is added to them. The **Incl. VAT / Excl. VAT** choice switches it on screen |
|
|
149
|
+
| `denominations` | none | Bills and coins for the round amounts; without them only the exact amount is offered |
|
|
150
|
+
| `onCharge` | none | `(total, ticket)`: `total` is the exact amount as plain text (`'12.50'`), `ticket` a `PosTicket`, plain JSON-safe data (`JSON.stringify` it as is): `{ currency?, taxInclusive, lines: [{ id, unitPrice, quantity, vatRate, discount?, total }], discount?, totals: { subtotal, discount, vatByRate: [{ rate, base, vat }], total } }`, every amount as text with the currency's decimals (`'12.50'`), rates in percent (`'5.5'`). The ticket is then cleared |
|
|
151
|
+
|
|
152
|
+
The amounts are exact decimals rounded to the currency's minor unit per line,
|
|
153
|
+
so the lines add up to the total. The ticket lives in memory only: it is never
|
|
154
|
+
written to `localStorage`, and the tape does not apply. The live region says
|
|
155
|
+
the total after a line is added or removed, the change or the amount due after
|
|
156
|
+
a tender, and the total charged; typing digits is not announced. Percentages
|
|
157
|
+
are whole numbers (7.5 % is not typeable) and quantities are whole.
|
|
158
|
+
|
|
159
|
+
## The Financial calculator
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
<Calculator defaultVariant="financial" currency="EUR" locale="fr" />
|
|
163
|
+
<Calculator variants={['financial']} />
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Financial is a panel of forms, not a keypad: four sub-tabs, each with the
|
|
167
|
+
library's own fields (`CurrencyField`, `PercentField`, `NumberField`) and its
|
|
168
|
+
results in a card below. The maths is
|
|
169
|
+
`@nxgt/material-core/calculator/financial`, exact decimals, amounts rounded to
|
|
170
|
+
the currency's minor unit (half-up).
|
|
171
|
+
|
|
172
|
+
| Tab | What it does |
|
|
173
|
+
| --- | --- |
|
|
174
|
+
| VAT | **Add VAT** to a price excluding VAT, or **Remove VAT** from one that includes it: price excluding VAT, VAT and price including VAT always add up |
|
|
175
|
+
| Margin | **Rates** of a cost and a selling price (margin is the share of the PRICE that is profit, markup the share of the COST, so 80 sold at 100 is a 20 % margin and a 25 % markup); **Price** from a cost and a margin or a markup; **Cost** from a price and a margin or a markup |
|
|
176
|
+
| % change | Percent change from one figure to another, and the difference (from `0` is an error) |
|
|
177
|
+
| Loan | Monthly payment of a loan (yearly rate, number of monthly payments, `0` % allowed), total interest, total paid, and the first 12 payments as a real `<table>` with a caption ("First 12 of 240 payments"): payment, interest, principal and balance, the last payment absorbing the rounding |
|
|
178
|
+
|
|
179
|
+
`currency` (an ISO 4217 code, shared with the point of sale; see
|
|
180
|
+
[the troubleshooting entry](../troubleshooting.md#the-financial-calculator-shows-no-currency))
|
|
181
|
+
is written after each amount and sets the decimals (`JPY` 0, `EUR` 2, `KWD`
|
|
182
|
+
3); without it amounts have two decimals and no code. Amounts and percents are
|
|
183
|
+
written in `locale`. Every tab keeps what was typed while another is open. A
|
|
184
|
+
result is read by the live region once the fields stop changing, not at each
|
|
185
|
+
digit, and an error (a margin of 100 % or more, a change from `0`) is read in
|
|
186
|
+
the same place. The fields hand over JavaScript `number`s, so a figure beyond
|
|
187
|
+
about 15 significant digits is out of range. The calculator keys, the tape and
|
|
188
|
+
`globalKeyboard` do not apply to this variant, and typing in a field never
|
|
189
|
+
reaches them.
|
|
190
|
+
|
|
191
|
+
## The conversion calculator
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
<Calculator defaultVariant="conversion" />
|
|
195
|
+
<Calculator
|
|
196
|
+
defaultVariant="conversion"
|
|
197
|
+
currencyRates={{ base: 'EUR', rates: { USD: '1.085', JPY: '160.5' }, asOf: '2026-10-28' }}
|
|
198
|
+
/>
|
|
199
|
+
<Calculator
|
|
200
|
+
defaultVariant="conversion"
|
|
201
|
+
currencyRates={(signal) => fetch('/api/rates', { signal }).then((r) => r.json())}
|
|
202
|
+
/>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
A converter on `@nxgt/material-core/calculator/units`; the tab is named
|
|
206
|
+
"Conversion". Choose a **Category** (length, mass, temperature, volume, area,
|
|
207
|
+
speed, time, data), type a **Value** (in the locale's own separators: `1 234,5`
|
|
208
|
+
in French) and pick the unit it is in (**From**) and the unit wanted (**To**).
|
|
209
|
+
The swap button turns the pair around and keeps the value; choosing on one side
|
|
210
|
+
the unit the other side has swaps them. The result is exact (`1 in` is `2.54
|
|
211
|
+
cm`, `212 °F` is `100 °C`; temperatures keep their offsets) and written in the
|
|
212
|
+
locale with up to 16 significant digits. The live region says it once the value
|
|
213
|
+
stops changing, not at every digit. The variant has no keypad, tape or memory,
|
|
214
|
+
and takes no calculator keys.
|
|
215
|
+
|
|
216
|
+
`currencyRates` adds a **Currency** category, and only then:
|
|
217
|
+
|
|
218
|
+
- An object `{ base, rates, asOf? }`: `rates[code]` is how much of `code` one
|
|
219
|
+
`base` buys, every rate a positive number or text (text keeps the digits
|
|
220
|
+
exact). `asOf` is shown as "Rates as of ...".
|
|
221
|
+
- A function `(signal: AbortSignal) => Promise<{ base, rates, asOf? }>`, called
|
|
222
|
+
the first time Currency is chosen, with an `AbortSignal` that aborts when the panel closes
|
|
223
|
+
or the fetch is repeated (pass it to `fetch`). Meanwhile the panel says
|
|
224
|
+
"Loading exchange rates..."; when the promise rejects or the rates are not
|
|
225
|
+
valid it says so, with **Try again**, which calls the function again. Its
|
|
226
|
+
identity does not matter (an inline arrow is fine); only Try again calls it
|
|
227
|
+
a second time. A function that throws at once is an error like a rejection.
|
|
228
|
+
|
|
229
|
+
A currency amount is rounded to the minor unit of the target currency (`JPY` 0,
|
|
230
|
+
`EUR` 2, `KWD` 3). Nothing is fetched by the library, and no rate is built in.
|
|
231
|
+
The types are `CalculatorCurrencyRates` (the object), `CalculatorRatesSource`
|
|
232
|
+
(the object or the function) and `CalculatorConversionProps`, exported from
|
|
233
|
+
`@nxgt/material/calculator`.
|
|
234
|
+
|
|
235
|
+
Currency names follow the i18n language (the one the unit names are translated
|
|
236
|
+
in); `locale` only formats the number and the quote date.
|
|
237
|
+
|
|
238
|
+
### Wording
|
|
239
|
+
|
|
240
|
+
The words live under `material.calculator.conversion` (categories, units,
|
|
241
|
+
`rates.loading`, `rates.error`, `rates.retry`, `rates.as-of`, the announcement);
|
|
242
|
+
the engine's messages are under `material.calculator.error`. Override one key
|
|
243
|
+
with `mergeResources` (per language, your value wins; see the
|
|
244
|
+
[i18n guide](./i18n.md)) and give the result to the provider:
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
import { mergeResources, resources as materialResources } from '@nxgt/material/i18n';
|
|
248
|
+
|
|
249
|
+
export const resources = mergeResources(materialResources, {
|
|
250
|
+
en: { material: { calculator: { conversion: { rates: { retry: 'Reload rates' } } } } },
|
|
251
|
+
});
|
|
252
|
+
// <I18nProvider resources={resources}>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
| Prop | Default | |
|
|
256
|
+
| --- | --- | --- |
|
|
257
|
+
| `currencyRates` | none | The rates, or a function that fetches them (above). None: no Currency category |
|
|
258
|
+
| `locale`, `precision`, `rounding` | | Read as everywhere: number format, significant digits and rounding of a result that does not terminate |
|
|
259
|
+
|
|
260
|
+
## The Programmer calculator
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
<Calculator defaultVariant="programmer" defaultWordSize={32} defaultSigned={false} />
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Integers in a word of 8, 16, 32 or 64 bits, signed (two's complement, the
|
|
267
|
+
default) or unsigned; every result wraps into the word (`127 + 1` is `-128` in
|
|
268
|
+
a signed 8-bit word). The maths is
|
|
269
|
+
`@nxgt/material-core/calculator/programmer`. The keypad adds `A` to `F`, the
|
|
270
|
+
word operators (`AND`, `OR`, `XOR`, `NOT`, `NAND`, `NOR`), shifts (`<<` and
|
|
271
|
+
`>>`, arithmetic) and rotates (`ROL`, `ROR`), and `mod`. `^` on the keyboard is
|
|
272
|
+
`XOR`; the `>>` key is an arithmetic shift (it copies the sign bit in), and the
|
|
273
|
+
logical shift `>>>` can be typed as text.
|
|
274
|
+
|
|
275
|
+
- **Bases**: four readouts (HEX, DEC, OCT, BIN) show the number being edited
|
|
276
|
+
and are a single choice: the base chosen is the one the digit keys type in
|
|
277
|
+
and the big line is written in. Changing it rewrites the number in the new
|
|
278
|
+
base: an expression that calculates (`10+5`) collapses to its value and the
|
|
279
|
+
live region says "Converted to F"; one that does not calculate yet (`10+(`)
|
|
280
|
+
has each number literal rewritten in place (`a+(`), as does one that ends in
|
|
281
|
+
an operator (`10+` is `a+` in hex, without collapsing), and one that cannot be
|
|
282
|
+
rewritten cleanly keeps its base and says "Base not changed". Digits the base
|
|
283
|
+
does not have (`A` to `F` in decimal, `8` and `9` in octal, `2` to `9` in
|
|
284
|
+
binary) are `aria-disabled` (they stay in the tab order), press nothing, and
|
|
285
|
+
say "Not available in Octal", from the keypad or the keyboard.
|
|
286
|
+
- **Word**: the size buttons and the **Signed** toggle change the word. A
|
|
287
|
+
narrower word cuts the number to its low bits and the live region says
|
|
288
|
+
"Value cut to 8 bits: 44"; a wider one, or a change of sign, rereads the same
|
|
289
|
+
bits.
|
|
290
|
+
- **Bit pad**: behind a **Bit pad** disclosure, one toggle button per bit
|
|
291
|
+
(`aria-pressed`, "Bit 7"), most significant first, grouped by four: one
|
|
292
|
+
nibble a row under 400px, two from 400, four from 760. Pressing a bit flips it
|
|
293
|
+
and announces it. While the expression does not calculate (`10+(`) the pad is
|
|
294
|
+
inert (`aria-disabled`) and leaves the expression alone.
|
|
295
|
+
- Copy writes the value in the base shown, upper case, with no prefix (`FF`);
|
|
296
|
+
Paste reads the text in the current base, so Copy then Paste round-trips. The
|
|
297
|
+
tape keeps the expression as typed and the result in decimal. Results are
|
|
298
|
+
announced in the chosen base.
|
|
299
|
+
|
|
300
|
+
`defaultWordSize` (`8 | 16 | 32 | 64`, default `64`) and `defaultSigned`
|
|
301
|
+
(default `true`) are read once, when the calculator mounts; the user changes
|
|
302
|
+
the word from then on.
|
|
303
|
+
|
|
304
|
+
## In a form: CalculatorField
|
|
305
|
+
|
|
306
|
+
`CalculatorField` and `CalculatorFormField` are their own entry,
|
|
307
|
+
`@nxgt/material/calculator-field`, so an app that only uses `Calculator` does
|
|
308
|
+
not pay for the popover and sheet. `CalculatorField` is a number field with an "Open calculator" button inside it.
|
|
309
|
+
The button opens a `Calculator` seeded with the field's number: a popover from
|
|
310
|
+
768px wide, a bottom sheet below. **Apply** writes the result to the field;
|
|
311
|
+
**Cancel** and Escape keep the number. Focus goes back to the button either way.
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
import { CalculatorField, CalculatorFormField } from '@nxgt/material/calculator-field';
|
|
315
|
+
|
|
316
|
+
<CalculatorField label="Quantity" value={qty} onChange={setQty} />
|
|
317
|
+
<CalculatorField label="Price" currency="EUR" value={price} onChange={setPrice} onExactValueChange={(exact) => console.log(exact)} />
|
|
318
|
+
<CalculatorFormField control={form.control} name="total" label="Total" currency="EUR" />
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
It is a `NumberField` (steppers, `min`, `max`, `step`, `suffix`), or a
|
|
322
|
+
`CurrencyField` when `currency` is set; a currency field takes no `suffix`, `step` or `hideSteppers`, and `min` / `max` do not limit what is typed (Apply still holds the amount to them). It adds:
|
|
323
|
+
|
|
324
|
+
| Prop | Default | |
|
|
325
|
+
| --- | --- | --- |
|
|
326
|
+
| `calculatorVariant` | `standard` | The variant the calculator opens with |
|
|
327
|
+
| `calculatorVariants` | `['standard']` | The variants its switcher offers; one hides the switcher. Pass more to opt in: `['standard', 'scientific', 'financial']` |
|
|
328
|
+
| `surface` | `auto` | `auto` (popover from 768px, sheet below), `popover` or `sheet` |
|
|
329
|
+
| `onExactValueChange` | none | Called on Apply with the exact decimal result (`'3.3333333333333333333333333333333333'`), before it is rounded |
|
|
330
|
+
| `fractionDigits` | the currency's | Decimals of a currency amount |
|
|
331
|
+
|
|
332
|
+
Apply takes what the display shows, so an unfinished sum (`2 + 3 × 4` with no
|
|
333
|
+
`=`) applies its result. A currency amount is rounded half-up to the currency's
|
|
334
|
+
decimals (`10 ÷ 3` is `3.33` in EUR, `1235` for `1234.5` in JPY); any other
|
|
335
|
+
number is the nearest `number`. The result is held to `min` and `max`, as typing
|
|
336
|
+
is. Apply is disabled while the display has no number (empty, or an error), see [troubleshooting](../troubleshooting.md#calculator). The
|
|
337
|
+
calculator keeps no tape or memory there (`persist={false}`), and each opening
|
|
338
|
+
starts from the field's number again.
|
|
339
|
+
|
|
340
|
+
`CalculatorFormField` takes `control` and `name`; the value is `number | null`.
|
|
341
|
+
Focus moving into the calculator and back is not leaving, so the field is
|
|
342
|
+
touched when focus leaves the field and its calculator.
|
|
343
|
+
|
|
344
|
+
Two props of `Calculator` serve it, and an application can use them too:
|
|
345
|
+
`defaultValue` (a number such as `'12.5'` the calculator opens with, as a
|
|
346
|
+
finished result: a digit starts a new number, an operator carries on from it)
|
|
347
|
+
and `onValueChange` (the display's exact value each time it changes, `''` when
|
|
348
|
+
there is none).
|
|
349
|
+
|
|
350
|
+
## Props
|
|
351
|
+
|
|
352
|
+
| Prop | Default | |
|
|
353
|
+
| --- | --- | --- |
|
|
354
|
+
| `variant` / `defaultVariant` / `onVariantChange` | `standard` | The variant shown, controlled or not. A variant that is not available yet falls back to Standard |
|
|
355
|
+
| `variants` | every registered variant | The variants the switcher offers; one hides the switcher. The default list grows with each variant the library adds, so an app that wants a fixed set passes `variants` |
|
|
356
|
+
| `currency` | none | ISO 4217 code of the amounts (decimals and code), see [above](#the-point-of-sale-calculator) |
|
|
357
|
+
| `vatRates`, `pricesIncludeVat`, `denominations`, `onCharge` | | Read only by the point of sale, [above](#the-point-of-sale-calculator) |
|
|
358
|
+
| `defaultWordSize`, `defaultSigned` | `64`, `true` | Read only by the Programmer variant, [above](#the-programmer-calculator) |
|
|
359
|
+
| `currencyRates` | none | Read only by Conversion: its Currency category, [above](#the-conversion-calculator) |
|
|
360
|
+
| `locale` | the page's language | Separators, grouping and the decimal key's glyph |
|
|
361
|
+
| `precision`, `rounding` | 34, `half-even` | The engine's context |
|
|
362
|
+
| `percent` | `contextual` | `contextual` (`100 + 10%` is 110) or `literal` (always `/100`) |
|
|
363
|
+
| `persist` | `true` | Keep the tape and memory in `localStorage`; `{ key }` names the slot; `false` keeps nothing |
|
|
364
|
+
| `feedback` | none | `{ haptics, sound }`, both off |
|
|
365
|
+
| `globalKeyboard` | `false` | Also take the keys typed anywhere on the page |
|
|
366
|
+
| `defaultValue` | none | A number the calculator opens with, as a finished result, see [CalculatorField](#in-a-form-calculatorfield) |
|
|
367
|
+
| `onValueChange` | none | `(value)`: the display's exact value (result or live preview) each time it changes; `''` when there is none |
|
|
368
|
+
| `onResult` | none | `(value, expression)` after each `=`: the exact result and the canonical expression |
|
|
369
|
+
| `className`, `aria-label` | | The root `role="group"`, named "Calculator" by default |
|
|
370
|
+
|
|
371
|
+
## Keyboard
|
|
372
|
+
|
|
373
|
+
The calculator takes the keys typed inside it (a key, the display or the
|
|
374
|
+
tape): digits, `.` and `,` (the locale's decimal), `+ - * / x`, `%`, `(` `)`,
|
|
375
|
+
`=` and Enter, Backspace, Delete (`CE`), Escape (`C`), and `Ctrl`/`Cmd` + `C`
|
|
376
|
+
(copy) and `V` (paste, the browser's own paste event). It reads `event.key`, so an AZERTY keyboard types the digits it
|
|
377
|
+
prints. Enter on a focused key is that key's click, not `=`.
|
|
378
|
+
|
|
379
|
+
In the Programmer variant `a` to `f` type the hex digits (only where the base
|
|
380
|
+
has them) and `^` is `XOR`; `&`, `|` and `~` are not mapped, use the `AND`,
|
|
381
|
+
`OR` and `NOT` keys. `>>` is an arithmetic shift, and `>>>` (logical) can be
|
|
382
|
+
typed as text.
|
|
383
|
+
|
|
384
|
+
The keypad is one tab stop. Inside it the arrow keys move over the grid in two
|
|
385
|
+
dimensions, Home and End along a row, and Ctrl with them to the first and last
|
|
386
|
+
key. Escape closes the history when it lies over the keypad, and means `C`
|
|
387
|
+
otherwise.
|
|
388
|
+
|
|
389
|
+
`globalKeyboard` adds a window listener for the keys typed elsewhere on the
|
|
390
|
+
page. It never takes a key typed in an input, a textarea, a select or an
|
|
391
|
+
editable element.
|
|
392
|
+
|
|
393
|
+
## Tape and memory
|
|
394
|
+
|
|
395
|
+
Each `=` writes an entry to the tape (newest first, 100 at most). Open it with
|
|
396
|
+
the history button; it takes the keypad's place below 720px and sits beside it
|
|
397
|
+
from there (the history button stays, and focus moves into the
|
|
398
|
+
history and back). The
|
|
399
|
+
expression button replays the entry into the display, ready to edit; the result
|
|
400
|
+
button types the result into the current expression. The bin clears the tape.
|
|
401
|
+
|
|
402
|
+
`MC MR M+ M−` clear, recall, add to and subtract from the memory, at full
|
|
403
|
+
precision. An `M` chip shows while the memory holds a value.
|
|
404
|
+
|
|
405
|
+
## Copy and paste
|
|
406
|
+
|
|
407
|
+
The copy button (or `Ctrl`/`Cmd` + `C` with nothing selected) copies the exact
|
|
408
|
+
result in the locale's decimal, without grouping. The paste button
|
|
409
|
+
(which asks the browser for clipboard permission) and `Ctrl`/`Cmd` + `V` (no
|
|
410
|
+
permission, it reads the paste event) put the clipboard's text in as the expression, accepting
|
|
411
|
+
the usual separators (`1.234,5 × 2` in German, `1,234.5 × 2` in English) and
|
|
412
|
+
Arabic-Indic digits; press `=` to calculate it. A browser that denies
|
|
413
|
+
clipboard access leaves the calculator as it was.
|
|
414
|
+
|
|
415
|
+
## What is stored
|
|
416
|
+
|
|
417
|
+
With `persist` on, `localStorage` holds `nxgt-calculator:<key>:history` (the
|
|
418
|
+
tape) and `nxgt-calculator:<key>:memory`, versioned JSON that is read after
|
|
419
|
+
mount and validated: anything unreadable gives an empty tape and a memory of
|
|
420
|
+
`0`. Writes are debounced. A blocked or full storage is ignored. Use
|
|
421
|
+
`persist={false}` where a calculator must not remember (a shared till), or a
|
|
422
|
+
`key` per till.
|
|
423
|
+
|
|
424
|
+
## Feedback
|
|
425
|
+
|
|
426
|
+
`feedback={{ haptics: true }}` vibrates 8 ms on a key press where
|
|
427
|
+
`navigator.vibrate` exists, and never under `prefers-reduced-motion`.
|
|
428
|
+
`feedback={{ sound: true }}` plays a short tick through the Web Audio API,
|
|
429
|
+
created on the first press. Both are off by default.
|
|
430
|
+
|
|
431
|
+
## Sizing
|
|
432
|
+
|
|
433
|
+
The calculator sizes itself by its own width (container queries), not the
|
|
434
|
+
window's: under 360px a compact layout, 360-599 a phone, 600-899 a tablet,
|
|
435
|
+
900 and up a desktop with a wider tape (where the tape sits is in
|
|
436
|
+
[Tape and memory](#tape-and-memory)). Long results shrink instead of clipping. Keys
|
|
437
|
+
are at least 44px on a coarse pointer. The result swap animation is off under
|
|
438
|
+
reduced motion, and forced colours get borders.
|
|
439
|
+
|
|
440
|
+
## Accessibility
|
|
441
|
+
|
|
442
|
+
- The root is a named `role="group"`; the keypad is a `role="group"` of native
|
|
443
|
+
buttons, each with a spoken name ("Plus", "Divided by", "Equals"); the glyph
|
|
444
|
+
is decoration.
|
|
445
|
+
- The display is a named group, not an input and not a tab stop. The expression and the result are read
|
|
446
|
+
left to right in a right-to-left page, as are the keys.
|
|
447
|
+
- A polite live region announces the result after `=`, errors, memory changes,
|
|
448
|
+
copy and paste, not every key.
|
|
449
|
+
- Errors are words ("Cannot divide by zero"), never `NaN` or `Infinity`.
|
|
450
|
+
|
|
451
|
+
## Translations
|
|
452
|
+
|
|
453
|
+
Every string is `material.calculator.*` in the base bundle, English and
|
|
454
|
+
French; override a leaf in your own resources.
|
|
455
|
+
|
|
456
|
+
The Programmer keys have their own leaves: `material.calculator.programmer.*`
|
|
457
|
+
(the bases and their `set-*` announcements, word size, `signed`, `bits`, `bit`,
|
|
458
|
+
`bit-on`, `bit-off`, `converted`, `base-kept`, `unavailable`), the key names
|
|
459
|
+
under `material.calculator.keys` (`hex-a` to `hex-f`, `and`, `or`, `xor`,
|
|
460
|
+
`not`, `nand`, `nor`, the shifts and rotates), and
|
|
461
|
+
`material.calculator.announce.truncated`, `wordSigned` and `wordUnsigned`.
|
|
462
|
+
|
|
463
|
+
`material.calculator.field.*` (`open`, `title`, `apply`, `cancel`) name the
|
|
464
|
+
`CalculatorField` button and its dialog.
|
|
465
|
+
|
|
466
|
+
## Troubleshooting
|
|
467
|
+
|
|
468
|
+
See [the Calculator entries](../troubleshooting.md#calculator).
|
package/docs/guides/forms.md
CHANGED
|
@@ -116,7 +116,7 @@ export function PlanForm() {
|
|
|
116
116
|
| --- | --- |
|
|
117
117
|
| one input (`TextFormField`, `EmailFormField`, `TextareaFormField`, `SwitchFormField`, `CheckboxFormField`, …) | its input loses focus, as a native `blur` |
|
|
118
118
|
| several controls (`OpeningHoursFormField`, inline by default: focus leaves the week editor and its phone sheet; `ContactsFormField`, inline by default: focus leaves the rows and the phone sheet; `AttributesFormField`, inline by default: focus leaves the rows, their open fields and the phone sheet; `PasswordFormField` and its eye button, `NumberFormField` and its steppers, `QuantityFormField`, `PhoneFormField`, `OtpFormField`, `SliderFormField` with two thumbs, `DurationFormField`, `RatingFormField`, `RadioGroupFormField`, `CheckboxGroupFormField`, `ChipGroupFormField`, `ChoiceCardGroupFormField`, `SortableListFormField`, `TransferListFormField`, `InlineEditFormField`, `LocalizedTextFormField`, `AttributeValuesFormFieldSet`, …) | focus leaves all of them; moving between them is not leaving |
|
|
119
|
-
| a picker (`SelectFormField`, `ComboboxFormField`, `AutocompleteFormField`, `TreeSelectFormField`, `CountryFormField`, `TimezoneFormField`, `ColorFormField`, `DateFormField`, `DateRangeFormField`, `TimeFormField`, …) | focus leaves the trigger **and** the popover it opened. Opening the popover, or picking in it, is not leaving; closing it hands focus back to the trigger, and the next Tab or click elsewhere is. A typed `DateFormField`, `DateRangeFormField` or `TimeFormField` is one trigger: moving between its segments (both ends of a range) and its buttons is not leaving |
|
|
119
|
+
| a picker (`SelectFormField`, `ComboboxFormField`, `AutocompleteFormField`, `TreeSelectFormField`, `CountryFormField`, `TimezoneFormField`, `ColorFormField`, `DateFormField`, `DateRangeFormField`, `TimeFormField`, `CalculatorFormField` (the number field and its calculator button), …) | focus leaves the trigger **and** the popover it opened. Opening the popover, or picking in it, is not leaving; closing it hands focus back to the trigger, and the next Tab or click elsewhere is. A typed `DateFormField`, `DateRangeFormField` or `TimeFormField` is one trigger: moving between its segments (both ends of a range) and its buttons is not leaving |
|
|
120
120
|
| a dialog editor (`PostalAddressFormField`, `ContactsFormField` with `editing="dialog"`, `OpeningHoursFormField` with `editing="dialog"`, `AttributesFormField` with `editing="dialog"`, and `LocationFormField` from `@nxgt/material/map`) | focus leaves its buttons and the dialog they open. Closing the dialog hands focus back to the button that opened it |
|
|
121
121
|
| an upload (`UploadFormField`, `NetworkUploadFormField`, `S3UploadFormField`, `ImageFormField`, `ImageS3FormField`, `FileListFormField`, `FileListS3FormField`) | focus leaves the drop zone and its buttons. Choosing a file in the browser's own dialog is not leaving |
|
|
122
122
|
| `RichTextEditorFormField`, `CodeEditorFormField` | focus leaves the editor and its toolbar |
|
|
@@ -277,7 +277,8 @@ form grows with the page, and the page is the one scroll. The actions
|
|
|
277
277
|
(`[data-slot="form-actions"]`) are sticky at the bottom of whatever scrolls
|
|
278
278
|
the form, on a translucent, blurred background, so Cancel and Save stay in
|
|
279
279
|
reach while the fields scroll under them; a form shorter than the screen
|
|
280
|
-
shows them right under its fields
|
|
280
|
+
shows them right under its fields, on the fields' own surface (same
|
|
281
|
+
tint, no gap): one slab, not two.
|
|
281
282
|
|
|
282
283
|
- In a `DialogContent` without a `DialogBody`, or a `SheetContent`, which are capped to the screen
|
|
283
284
|
and scroll themselves, the actions stick to the dialog's or the sheet's
|
|
@@ -488,6 +489,7 @@ or fails validation.
|
|
|
488
489
|
| `PercentField` · `PercentFormField` | `number \| null`, `min` 0, `max` 100, `step` 1 by default | `null` |
|
|
489
490
|
| `QuantityField` · `QuantityFormField` | `{ value: number \| null, unit: string }`. An error on the field, `.value` or `.unit` shows as one message under the pair | `{ value: null, unit: '' }` |
|
|
490
491
|
| `CurrencyField` · `CurrencyFormField` | `number \| null`, the amount only, not rounded. `currency` (default `'EUR'`) and `fractionDigits` (the currency's own decimals by default) are display | `null` |
|
|
492
|
+
| `CalculatorField` · `CalculatorFormField` (`@nxgt/material/calculator-field`) | `number \| null`. `null` when empty; what Apply writes (a currency amount rounded half-up to its decimals, held to `min` / `max`). `onExactValueChange` gets the exact decimal string | `null` |
|
|
491
493
|
| `PhoneField` · `PhoneFormField` | E.164 `string` (`'+33612345678'`), or `null` when empty. `PhoneFormField` reports a non-empty number that is not yet possible as the field error `material.phone-field.incomplete`; `PhoneField` signals it with `onValidityChange`. `defaultCountry` is `'FR'` | `null` |
|
|
492
494
|
| `UrlField` · `UrlFormField` | `string` (as typed) | `''` |
|
|
493
495
|
| `SearchField` · `SearchFormField` | `string`, after `debounceMs` (default `0`) | `''` |
|
package/docs/guides/i18n.md
CHANGED
|
@@ -515,6 +515,11 @@ them the merged resources (see "Overriding a component's words" below).
|
|
|
515
515
|
<Spinner variant="4" /> // role="img" aria-label="Chargement..."
|
|
516
516
|
```
|
|
517
517
|
|
|
518
|
+
The calculator's loading state reads `material.calculator.loading` ("Loading the
|
|
519
|
+
calculator"), `material.calculator.load-failed` ("This calculator could not be
|
|
520
|
+
loaded.") and `material.calculator.retry` ("Try again"), shown while a variant
|
|
521
|
+
other than Standard loads on demand or when its download failed.
|
|
522
|
+
|
|
518
523
|
### Overriding a component's words
|
|
519
524
|
|
|
520
525
|
Give the provider the merged resources and every component translates through
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/roadmap.md
CHANGED
|
@@ -6,8 +6,14 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
6
6
|
|
|
7
7
|
## Now
|
|
8
8
|
|
|
9
|
-
- **Calculator** — `@nxgt/material/calculator`
|
|
10
|
-
|
|
9
|
+
- **Calculator** — `@nxgt/material/calculator` is an exact-decimal calculator
|
|
10
|
+
(Standard, Scientific, point of sale, Financial, Conversion, Programmer;
|
|
11
|
+
every variant but Standard loads on demand)
|
|
12
|
+
with a tape, a memory, the keyboard and screen-reader announcements, and
|
|
13
|
+
`@nxgt/material/calculator-field` adds `CalculatorField`, a number or
|
|
14
|
+
currency field whose button opens it. Its stylesheet is opt-in:
|
|
15
|
+
import `@nxgt/material/calculator.css` after `styles.css`
|
|
16
|
+
([guide](guides/calculator.md)).
|
|
11
17
|
- **Barcodes and label sheets** — `@nxgt/material/barcode` draws Code 128
|
|
12
18
|
and Data Matrix as accessible SVG (themed, dark-aware, black on white in
|
|
13
19
|
print) and lays labels out on a sheet to print: label size, columns, rows,
|
|
@@ -371,7 +377,7 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
371
377
|
|
|
372
378
|
## Shipped
|
|
373
379
|
|
|
374
|
-
- **Moment (
|
|
380
|
+
- **Moment (3.74.0)** — a transient full-screen announcement for a one-off event (a player is eliminated, a role is revealed): a modal dialog named by its title, with an illustration, description, action and tone, dismissed by Escape, a tap, its action or a timer, and no motion under reduced motion ([#2220](https://github.com/softistx/nxgt-material/issues/2220), [#2247](https://github.com/softistx/nxgt-material/pull/2247)). A `modal={false}` variant for live events (focus stays, taps pass through, polite status) follows in the next minor ([#2313](https://github.com/softistx/nxgt-material/issues/2313)).
|
|
375
381
|
- **RecordActionsMenu (next minor)** — one menu for a record's lifecycle: archive with an Undo toast (or confirm first with `archivePolicy="confirm"`), restore, and delete that always confirms and shows the backend's refusal, with `ConfirmDialog` gaining `details` and `refusal` slots.
|
|
376
382
|
- **Assistant approval card (next minor)** — `ChatActionProposal` shows an action an assistant proposes, with its status, deadline and Confirm / Reject, and `ChatToolActivity` is a compact row for a tool step in a chat thread ([#2134](https://github.com/softistx/nxgt-material/issues/2134)).
|
|
377
383
|
|