@adecore/ui 0.39.0 → 0.40.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/dist/AccentSwatches.js +2 -3
- package/dist/Banner.js +1 -6
- package/dist/ChoiceCards.js +0 -5
- package/dist/ColorSwatch.js +1 -4
- package/dist/ColorWheelPicker.js +3 -6
- package/dist/DockShell.js +3 -5
- package/dist/EmptyState.js +0 -1
- package/dist/ErrorBoundary.js +1 -5
- package/dist/Field.js +2 -6
- package/dist/FileIcon.js +2 -4
- package/dist/Icon.js +1 -2
- package/dist/IconButton.js +1 -1
- package/dist/IconPicker.js +3 -7
- package/dist/Input.js +1 -2
- package/dist/Kbd.js +1 -3
- package/dist/LazyBoundary.js +2 -3
- package/dist/Meter.js +0 -1
- package/dist/MiddleTruncate.js +2 -6
- package/dist/PanelEmpty.js +0 -1
- package/dist/PanelHeader.js +1 -4
- package/dist/Pill.js +1 -6
- package/dist/ProjectSwitcher.js +1 -1
- package/dist/PromptDialog.js +5 -8
- package/dist/RelativeTime.js +1 -1
- package/dist/SegmentBar.js +1 -2
- package/dist/Segmented.js +2 -5
- package/dist/Select.js +1 -4
- package/dist/ShortcutHints.js +2 -3
- package/dist/Slider.js +0 -1
- package/dist/SlidingColumn.js +2 -4
- package/dist/SplitButton.js +1 -5
- package/dist/TextMenu.js +1 -5
- package/dist/Tile.js +0 -4
- package/dist/Toasts.js +1 -9
- package/dist/Tooltip.js +1 -1
- package/dist/UIProvider.js +0 -5
- package/dist/Waveform.js +4 -2
- package/dist/Wipe.js +1 -6
- package/dist/ZoomControls.js +0 -1
- package/dist/clipboard.js +2 -5
- package/dist/combobox/parts.js +3 -9
- package/dist/command-palette/parts.js +5 -14
- package/dist/dialog/parts.js +5 -10
- package/dist/dialog-layer.js +2 -3
- package/dist/error-boundary.js +4 -20
- package/dist/file-icon.js +4 -9
- package/dist/file-tree/empty-lines.js +2 -8
- package/dist/file-tree/use-empty-lines.js +1 -5
- package/dist/file-tree/use-slots.js +6 -10
- package/dist/format/datetime.js +32 -29
- package/dist/format/duration.js +2 -10
- package/dist/format/locale.js +19 -39
- package/dist/format/number.js +9 -22
- package/dist/format/regions.js +4 -7
- package/dist/icon-picker.js +5 -14
- package/dist/key-value-list/parts.js +1 -5
- package/dist/lazy.js +4 -19
- package/dist/locales.js +2 -6
- package/dist/menu/parts.js +61 -133
- package/dist/middle-truncate.js +2 -3
- package/dist/placement.js +0 -1
- package/dist/popover/parts.js +1 -5
- package/dist/popup-layer.js +2 -4
- package/dist/prefetch.js +2 -5
- package/dist/selection.js +1 -5
- package/dist/settings/MasterDetail.js +1 -7
- package/dist/settings/SettingsDialog.js +1 -2
- package/dist/settings/SettingsRow.js +2 -5
- package/dist/settings/SettingsSection.js +1 -1
- package/dist/shortcut-hints.js +1 -5
- package/dist/shortcut.js +1 -2
- package/dist/tabs/overflow.js +1 -6
- package/dist/tabs/parts.js +69 -95
- package/dist/testing/dedupe.js +5 -7
- package/dist/tint.js +3 -5
- package/dist/toast-store.js +2 -10
- package/dist/tree/use-tree-shift.js +2 -6
- package/dist/useColumnResize.js +9 -10
- package/dist/useNow.js +2 -9
- package/dist/workspace/DropPreview.js +1 -5
- package/dist/workspace/preview.js +4 -9
- package/package.json +9 -9
- package/src/AccentSwatches.tsx +9 -3
- package/src/Banner.tsx +5 -11
- package/src/Button.tsx +4 -0
- package/src/Checkbox.tsx +3 -0
- package/src/ChoiceCards.tsx +12 -11
- package/src/CloseButton.tsx +1 -0
- package/src/ColorSwatch.tsx +7 -8
- package/src/ColorWheelPicker.tsx +28 -12
- package/src/ColumnResizeHandle.tsx +1 -0
- package/src/CopyButton.tsx +6 -0
- package/src/DisabledReason.tsx +1 -0
- package/src/DockShell.tsx +11 -10
- package/src/EmptyState.tsx +10 -6
- package/src/ErrorBoundary.tsx +13 -10
- package/src/Field.tsx +11 -13
- package/src/FileIcon.tsx +4 -4
- package/src/Icon.tsx +2 -4
- package/src/IconButton.tsx +14 -5
- package/src/IconPicker.tsx +30 -15
- package/src/Input.tsx +11 -9
- package/src/Kbd.tsx +8 -7
- package/src/LazyBoundary.tsx +3 -3
- package/src/Meter.tsx +7 -2
- package/src/MiddleTruncate.tsx +15 -6
- package/src/PanelEmpty.tsx +9 -7
- package/src/PanelHeader.tsx +2 -5
- package/src/Pill.tsx +7 -8
- package/src/ProjectSwitcher.tsx +16 -6
- package/src/PromptDialog.tsx +31 -26
- package/src/RelativeTime.tsx +6 -1
- package/src/SegmentBar.tsx +22 -11
- package/src/Segmented.tsx +16 -11
- package/src/Select.tsx +7 -4
- package/src/SelectSearch.tsx +3 -0
- package/src/ShortcutHints.tsx +24 -3
- package/src/Skeleton.tsx +1 -0
- package/src/Slider.tsx +4 -1
- package/src/SlidingColumn.tsx +18 -14
- package/src/Spinner.tsx +1 -0
- package/src/SplitButton.tsx +8 -8
- package/src/Stepper.tsx +6 -0
- package/src/Switch.tsx +2 -0
- package/src/TextMenu.tsx +2 -5
- package/src/Tile.tsx +2 -6
- package/src/Toasts.tsx +8 -12
- package/src/Tooltip.tsx +10 -5
- package/src/UIProvider.tsx +7 -7
- package/src/Waveform.tsx +41 -12
- package/src/Wipe.tsx +5 -6
- package/src/ZoomControls.tsx +5 -2
- package/src/clipboard.ts +4 -5
- package/src/combobox/parts.tsx +18 -14
- package/src/command-palette/context.ts +2 -0
- package/src/command-palette/index.parts.ts +1 -0
- package/src/command-palette/parts.tsx +20 -14
- package/src/command-palette/virtual.tsx +21 -0
- package/src/dialog/parts.tsx +10 -13
- package/src/dialog-layer.ts +5 -3
- package/src/error-boundary.ts +7 -20
- package/src/file-icon.ts +8 -9
- package/src/file-tree/empty-lines.ts +24 -8
- package/src/file-tree/helpers.ts +34 -0
- package/src/file-tree/highlight.ts +19 -0
- package/src/file-tree/index.parts.ts +1 -0
- package/src/file-tree/parts.tsx +41 -5
- package/src/file-tree/use-empty-lines.ts +22 -5
- package/src/file-tree/use-file-tree-shift.tsx +10 -0
- package/src/file-tree/use-file-tree.ts +2 -0
- package/src/file-tree/use-slots.ts +77 -12
- package/src/format/datetime.ts +42 -17
- package/src/format/duration.ts +28 -10
- package/src/format/index.ts +3 -0
- package/src/format/locale.ts +33 -42
- package/src/format/number.ts +21 -27
- package/src/format/regions.ts +4 -7
- package/src/icon-picker.ts +23 -16
- package/src/index.ts +8 -0
- package/src/key-value-list/parts.tsx +1 -5
- package/src/lazy-landings.ts +2 -0
- package/src/lazy.tsx +23 -19
- package/src/locales.ts +2 -6
- package/src/match.ts +14 -0
- package/src/menu/parts.tsx +30 -55
- package/src/middle-truncate.ts +12 -3
- package/src/modality.ts +4 -0
- package/src/placement.ts +2 -1
- package/src/platform.ts +2 -0
- package/src/popover/parts.tsx +3 -5
- package/src/popup-layer.ts +6 -4
- package/src/prefetch.ts +18 -5
- package/src/project-switcher-row.tsx +2 -0
- package/src/segmented-keys.ts +6 -0
- package/src/select-shared.ts +2 -0
- package/src/selection.ts +5 -5
- package/src/settings/ConfirmDialog.tsx +3 -0
- package/src/settings/MasterDetail.tsx +3 -9
- package/src/settings/SettingsDialog.tsx +27 -9
- package/src/settings/SettingsRow.tsx +16 -10
- package/src/settings/SettingsSection.tsx +10 -5
- package/src/settings/index.ts +3 -0
- package/src/settings/target.ts +1 -0
- package/src/shortcut-hints.ts +10 -5
- package/src/shortcut.ts +26 -6
- package/src/tabs/overflow.ts +8 -6
- package/src/tabs/parts.tsx +50 -26
- package/src/testing/dedupe.ts +27 -7
- package/src/testing/fake-source.ts +1 -0
- package/src/tint.ts +3 -5
- package/src/toast-store.ts +20 -14
- package/src/tree/parts.tsx +8 -0
- package/src/tree/shift.ts +6 -0
- package/src/tree/use-tree-shift.tsx +23 -7
- package/src/useAsyncAction.ts +8 -0
- package/src/useColumnResize.ts +24 -15
- package/src/useContentSize.ts +5 -0
- package/src/useMeasuredWidth.ts +1 -0
- package/src/useNow.ts +6 -11
- package/src/workspace/DropPreview.tsx +3 -5
- package/src/workspace/SplitView.tsx +109 -0
- package/src/workspace/TabStrip.tsx +42 -0
- package/src/workspace/Workspace.tsx +5 -0
- package/src/workspace/context.ts +1 -0
- package/src/workspace/geometry.ts +49 -0
- package/src/workspace/model.ts +72 -0
- package/src/workspace/preview.ts +15 -15
package/dist/combobox/parts.js
CHANGED
|
@@ -9,12 +9,11 @@ import { Kbd } from "../Kbd.js";
|
|
|
9
9
|
import { MENU_LABEL } from "../menu/parts.js";
|
|
10
10
|
import { splitPlacement } from '../placement.js';
|
|
11
11
|
import { renderPositioner } from '../popup-layer.js';
|
|
12
|
-
/*
|
|
12
|
+
/* It takes no room while it has nothing to say. */
|
|
13
13
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
14
|
const LIST_NOTE = 'text-center text-xs text-text-faint not-empty:px-3 not-empty:py-4';
|
|
15
15
|
/* The field keeps free text: Base UI's autocomplete, whose suggestions only offer text, rather than its combobox, which holds a value. */
|
|
16
16
|
export const ComboboxRoot = Autocomplete.Root;
|
|
17
|
-
/* The field the suggestions open under, drawn as the library's `Input`. */
|
|
18
17
|
export function ComboboxInput(t0) {
|
|
19
18
|
const $ = _c(39);
|
|
20
19
|
let className;
|
|
@@ -172,7 +171,6 @@ export function ComboboxInput(t0) {
|
|
|
172
171
|
}
|
|
173
172
|
return t15;
|
|
174
173
|
}
|
|
175
|
-
/* The portal, the positioner and the menu surface of the suggestions: under the field and at least as wide as it. */
|
|
176
174
|
export function ComboboxPopup(t0) {
|
|
177
175
|
const $ = _c(17);
|
|
178
176
|
let align;
|
|
@@ -278,11 +276,7 @@ export function ComboboxList(props) {
|
|
|
278
276
|
}
|
|
279
277
|
return t1;
|
|
280
278
|
}
|
|
281
|
-
/*
|
|
282
|
-
* One suggestion. Its children are the label. `onClick` runs for a click and for Enter on the
|
|
283
|
-
* highlighted row; Base UI clicks the row for Enter, so a modifier held with Enter is read in the
|
|
284
|
-
* field's `onKeyDown` instead.
|
|
285
|
-
*/
|
|
279
|
+
/* Base UI clicks the row for Enter, so a modifier held with Enter is read in the field's `onKeyDown` instead. */
|
|
286
280
|
export function ComboboxItem(t0) {
|
|
287
281
|
const $ = _c(36);
|
|
288
282
|
let children;
|
|
@@ -515,7 +509,7 @@ export function ComboboxEmpty(t0) {
|
|
|
515
509
|
}
|
|
516
510
|
return t2;
|
|
517
511
|
}
|
|
518
|
-
/*
|
|
512
|
+
/* Read out as it changes. It stays mounted; only its children come and go. */
|
|
519
513
|
export function ComboboxStatus(t0) {
|
|
520
514
|
const $ = _c(8);
|
|
521
515
|
let className;
|
|
@@ -20,11 +20,7 @@ const SIZE = {
|
|
|
20
20
|
md: 'w-[576px]',
|
|
21
21
|
lg: 'w-[760px]'
|
|
22
22
|
};
|
|
23
|
-
/*
|
|
24
|
-
* A dialog around a list that is always open. `open` and its handlers are the dialog's; the rest
|
|
25
|
-
* is Base UI's autocomplete, so the query, the items and their filter work as in a combobox. The
|
|
26
|
-
* first row is highlighted and stays so while the pointer leaves the list, which is what Enter runs.
|
|
27
|
-
*/
|
|
23
|
+
/* `open` and its handlers are the dialog's; the rest is Base UI's autocomplete. The first row stays highlighted while the pointer leaves the list, which is what Enter runs. */
|
|
28
24
|
export function CommandPaletteRoot({
|
|
29
25
|
open,
|
|
30
26
|
defaultOpen,
|
|
@@ -46,8 +42,7 @@ export function CommandPaletteRoot({
|
|
|
46
42
|
const [focusHighlight, setFocusHighlight] = useState(false);
|
|
47
43
|
/*
|
|
48
44
|
* Base UI moves the highlight to the first row for a typed query only. For a query the app sets,
|
|
49
|
-
* the list is empty for one commit
|
|
50
|
-
* puts it on the first row of what comes back.
|
|
45
|
+
* the list is empty for one unpainted commit, so Base UI highlights the first row of what comes back.
|
|
51
46
|
*/
|
|
52
47
|
const [settledValue, setSettledValue] = useState(value);
|
|
53
48
|
const resetting = value !== undefined && value !== settledValue;
|
|
@@ -120,10 +115,7 @@ export function CommandPaletteRoot({
|
|
|
120
115
|
})
|
|
121
116
|
});
|
|
122
117
|
}
|
|
123
|
-
/*
|
|
124
|
-
* The dialog's surface. It hangs from a fixed line near the top instead of the middle: the list
|
|
125
|
-
* changes height with every key, and a centered popup would walk up and down the screen.
|
|
126
|
-
*/
|
|
118
|
+
/* It hangs from a fixed line near the top: the list changes height with every key, and a centered popup would walk up and down. */
|
|
127
119
|
export function CommandPalettePopup(t0) {
|
|
128
120
|
const $ = _c(15);
|
|
129
121
|
let className;
|
|
@@ -189,7 +181,7 @@ export function CommandPalettePopup(t0) {
|
|
|
189
181
|
}
|
|
190
182
|
return t5;
|
|
191
183
|
}
|
|
192
|
-
/*
|
|
184
|
+
/* It keeps the keys while the arrows move the highlight; a control beside it should not take the focus on a click. */
|
|
193
185
|
export function CommandPaletteInput(t0) {
|
|
194
186
|
const $ = _c(29);
|
|
195
187
|
let className;
|
|
@@ -312,7 +304,7 @@ export function CommandPaletteInput(t0) {
|
|
|
312
304
|
}
|
|
313
305
|
return t11;
|
|
314
306
|
}
|
|
315
|
-
/*
|
|
307
|
+
/* It scrolls on its own, so the field and the footer stay put. */
|
|
316
308
|
export function CommandPaletteList(t0) {
|
|
317
309
|
const $ = _c(21);
|
|
318
310
|
let className;
|
|
@@ -406,7 +398,6 @@ export function CommandPaletteList(t0) {
|
|
|
406
398
|
}
|
|
407
399
|
return t6;
|
|
408
400
|
}
|
|
409
|
-
/* Under the list: the keys that work here, a count, an action that leaves the palette. */
|
|
410
401
|
export function CommandPaletteFooter(t0) {
|
|
411
402
|
const $ = _c(14);
|
|
412
403
|
let className;
|
package/dist/dialog/parts.js
CHANGED
|
@@ -5,10 +5,9 @@ import { Dialog as BaseDialog } from '@base-ui/react/dialog';
|
|
|
5
5
|
import { useRender } from '@base-ui/react/use-render';
|
|
6
6
|
import { withClass } from '../class-name.js';
|
|
7
7
|
import { useDialogLayer } from '../dialog-layer.js';
|
|
8
|
-
/* Whether the dialog is open, for its popup to decide whether it stacks over another one. */
|
|
9
8
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
9
|
const DialogOpenContext = createContext(false);
|
|
11
|
-
/*
|
|
10
|
+
/* Every question is as wide as the others, whatever it asks. */
|
|
12
11
|
const SIZE = {
|
|
13
12
|
sm: 'w-[420px] p-5'
|
|
14
13
|
};
|
|
@@ -83,11 +82,7 @@ export function DialogRoot(t0) {
|
|
|
83
82
|
}
|
|
84
83
|
export const DialogTrigger = BaseDialog.Trigger;
|
|
85
84
|
export const DialogClose = BaseDialog.Close;
|
|
86
|
-
/*
|
|
87
|
-
* The portal, the backdrop and the popup of a dialog in one part. A dialog that opens while another
|
|
88
|
-
* one is up, such as one from the menu bar over a settings dialog, takes the nested steps and a
|
|
89
|
-
* backdrop of its own, or the one underneath stays on top and keeps taking clicks.
|
|
90
|
-
*/
|
|
85
|
+
/* The portal, the backdrop and the popup of a dialog in one part; `useDialogLayer` says whether it stacks. */
|
|
91
86
|
export function DialogPopup(t0) {
|
|
92
87
|
const $ = _c(23);
|
|
93
88
|
let backdropClassName;
|
|
@@ -225,7 +220,7 @@ const DESCRIPTION = {
|
|
|
225
220
|
sm: 'text-sm text-text-muted',
|
|
226
221
|
xs: 'text-xs text-text-muted'
|
|
227
222
|
};
|
|
228
|
-
/*
|
|
223
|
+
/* What a screen reader reads as the dialog's description. It carries no margin. */
|
|
229
224
|
export function DialogDescription(t0) {
|
|
230
225
|
const $ = _c(10);
|
|
231
226
|
let className;
|
|
@@ -271,7 +266,7 @@ export function DialogDescription(t0) {
|
|
|
271
266
|
}
|
|
272
267
|
return t4;
|
|
273
268
|
}
|
|
274
|
-
/*
|
|
269
|
+
/* Styled as the description without being the dialog's description. */
|
|
275
270
|
export function DialogText(t0) {
|
|
276
271
|
const $ = _c(16);
|
|
277
272
|
let className;
|
|
@@ -340,7 +335,7 @@ export function DialogText(t0) {
|
|
|
340
335
|
}
|
|
341
336
|
return useRender(t5);
|
|
342
337
|
}
|
|
343
|
-
/* The
|
|
338
|
+
/* The main action goes last, and so on the right. */
|
|
344
339
|
export function DialogFooter(t0) {
|
|
345
340
|
const $ = _c(14);
|
|
346
341
|
let className;
|
package/dist/dialog-layer.js
CHANGED
|
@@ -3,9 +3,8 @@ import { useLayoutEffect, useRef, useState } from 'react';
|
|
|
3
3
|
// The app-level dialogs open right now. Each one is its own root, so Base UI does not see them as nested.
|
|
4
4
|
const open = new Set();
|
|
5
5
|
/*
|
|
6
|
-
* Whether a dialog opened
|
|
7
|
-
*
|
|
8
|
-
* `dialog-popup-nested`, a forced backdrop), or the one underneath stays on top and keeps taking clicks.
|
|
6
|
+
* Whether a dialog opened over another app-level dialog. Such a dialog takes the nested steps
|
|
7
|
+
* (`dialog-backdrop-nested`, `dialog-popup-nested`, a forced backdrop), or the one underneath stays on top and keeps taking clicks.
|
|
9
8
|
*/
|
|
10
9
|
export function useDialogLayer(isOpen) {
|
|
11
10
|
const $ = _c(5);
|
package/dist/error-boundary.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
* out of the message. Kept apart so it can be tested without a DOM.
|
|
4
|
-
*/
|
|
5
|
-
/*
|
|
6
|
-
* Whether a boundary that holds an error should draw its children again. Only a boundary that
|
|
7
|
-
* failed resets. Comparing keys while the children are fine would remount a terminal or an embedded
|
|
8
|
-
* page every time the data under it changes.
|
|
9
|
-
*/
|
|
1
|
+
/* The pure half of `ErrorBoundary`, kept apart so it can be tested without a DOM. */
|
|
2
|
+
/* Only a failed boundary resets: comparing keys while the children are fine would remount a terminal or an embedded page on every change. */
|
|
10
3
|
export const shouldReset = (failed, previous, next) => {
|
|
11
4
|
if (!failed) {
|
|
12
5
|
return false;
|
|
@@ -17,18 +10,9 @@ export const shouldReset = (failed, previous, next) => {
|
|
|
17
10
|
return previous.some((key, i) => !Object.is(key, next[i]));
|
|
18
11
|
};
|
|
19
12
|
/* A thrown value is not always an Error, and the message has to say something either way. */
|
|
20
|
-
export const errorMessageOf = error =>
|
|
21
|
-
if (error instanceof Error) {
|
|
22
|
-
return error.message || error.name;
|
|
23
|
-
}
|
|
24
|
-
return typeof error === 'string' ? error : String(error);
|
|
25
|
-
};
|
|
13
|
+
export const errorMessageOf = error => error instanceof Error ? error.message || error.name : String(error);
|
|
26
14
|
/* The text behind the copy button: what a bug report needs, the component stack included. */
|
|
27
15
|
export const errorReport = (label, error, componentStack) => {
|
|
28
16
|
const stack = error instanceof Error && error.stack ? error.stack : errorMessageOf(error);
|
|
29
|
-
|
|
30
|
-
if (componentStack) {
|
|
31
|
-
parts.push(`Component stack:${componentStack}`);
|
|
32
|
-
}
|
|
33
|
-
return parts.join('\n\n');
|
|
17
|
+
return [label, stack, ...(componentStack ? [`Component stack:${componentStack}`] : [])].join('\n\n');
|
|
34
18
|
};
|
package/dist/file-icon.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { createFileTreeIconResolver } from '@pierre/trees';
|
|
2
2
|
import { SETI_BY_FILE_EXTENSION, SETI_BY_FILE_NAME, SETI_BY_FILE_NAME_CONTAINS, SETI_DEFAULT_SYMBOL, SETI_SPRITE_SHEET } from './seti-icons.js';
|
|
3
3
|
const SPRITE_ELEMENT_ID = 'adecore-ui-file-icon-sprite';
|
|
4
|
-
/*
|
|
5
|
-
|
|
6
|
-
sprite brings the rules that color it. Everything drawn beside a tree calls `fileIconFor`, so a tab,
|
|
7
|
-
a picker row and a tree row never disagree about what a file is. */
|
|
4
|
+
/* Seti knows far more file types than the tree's own sets. The tree colors only those, so every symbol
|
|
5
|
+
carries its hue in its id and the sprite brings the rules that color it. */
|
|
8
6
|
export const FILE_TREE_ICONS = {
|
|
9
7
|
set: 'none',
|
|
10
8
|
spriteSheet: SETI_SPRITE_SHEET,
|
|
@@ -22,11 +20,8 @@ const resolveIcon = (...args) => {
|
|
|
22
20
|
return resolver.resolveIcon(...args);
|
|
23
21
|
};
|
|
24
22
|
/*
|
|
25
|
-
* The id of
|
|
26
|
-
*
|
|
27
|
-
* a part of the name (`Dockerfile.dev`), then by the longest extension that matches (`spec.ts` before
|
|
28
|
-
* `ts`). Anything else falls back to the generic file icon, a directory included: the tree marks a
|
|
29
|
-
* folder with its chevron, not a glyph.
|
|
23
|
+
* The id of a `<symbol>` in the sprite `mountFileIconSprite` puts in the document. A directory gets the
|
|
24
|
+
* generic file icon: the tree marks a folder with its chevron, not a glyph.
|
|
30
25
|
*/
|
|
31
26
|
export const fileIconFor = path => resolveIcon('file-tree-icon-file', path).name;
|
|
32
27
|
/* The tree carries the sprite into its own shadow root, out of reach of anything that draws an
|
|
@@ -13,10 +13,7 @@ export function isEmptyLine(path) {
|
|
|
13
13
|
export function directoryOfEmptyLine(path) {
|
|
14
14
|
return path.slice(0, -EMPTY_LINE_NAME.length);
|
|
15
15
|
}
|
|
16
|
-
/*
|
|
17
|
-
* The lines to add and the ones to take away: an open directory whose label is not undefined and
|
|
18
|
-
* that holds nothing besides its own line gets one, every other line the wrapper added goes.
|
|
19
|
-
*/
|
|
16
|
+
/* An open, labeled directory that holds nothing besides its own line gets one; every other line the wrapper added goes. */
|
|
20
17
|
export function emptyLineChanges(rows, labelOf, has, added) {
|
|
21
18
|
const wanted = new Set();
|
|
22
19
|
rows.forEach((row, index) => {
|
|
@@ -38,10 +35,7 @@ export function emptyLineChanges(rows, labelOf, has, added) {
|
|
|
38
35
|
remove: [...added].filter(line => !wanted.has(line) && has(line))
|
|
39
36
|
};
|
|
40
37
|
}
|
|
41
|
-
/*
|
|
42
|
-
* Where an arrow, Home or End goes instead when the row it would land on is a line: past it, or
|
|
43
|
-
* nowhere (the focused path itself) where nothing lies past it. Null when no line is in the way.
|
|
44
|
-
*/
|
|
38
|
+
/* Past the line the key would land on, or the focused path itself where nothing lies past it. Null when no line is in the way. */
|
|
45
39
|
export function pastEmptyLine(model, key) {
|
|
46
40
|
const index = model.getFocusedIndex();
|
|
47
41
|
const focused = model.getFocusedPath();
|
|
@@ -6,11 +6,7 @@ const POINTER_EVENTS = ['pointerdown', 'mousedown', 'click', 'dblclick', 'auxcli
|
|
|
6
6
|
function onEmptyLine(event) {
|
|
7
7
|
return event.composedPath().some(node => node instanceof HTMLElement && node.dataset.emptyLine === 'true');
|
|
8
8
|
}
|
|
9
|
-
/*
|
|
10
|
-
* Keeps a line under every open directory that is known to be empty, and keeps the line out of
|
|
11
|
-
* reach: a pointer on it does nothing and a key passes it. Returns what to call with every key the
|
|
12
|
-
* tree hears, after anything that notes where focus was.
|
|
13
|
-
*/
|
|
9
|
+
/* A pointer on a line does nothing and a key passes it. Call what it returns with every key the tree hears, after anything that notes where focus was. */
|
|
14
10
|
export function useEmptyLines(model, frame, emptyLabel) {
|
|
15
11
|
const $ = _c(12);
|
|
16
12
|
const latest = useRef(emptyLabel);
|
|
@@ -5,9 +5,8 @@ import { pathOfRow, visibleRows, visibleRowsAround } from './helpers.js';
|
|
|
5
5
|
import { matchHighlight, rangesOfMatches } from './highlight.js';
|
|
6
6
|
import { FILE_TREE_CSS } from './style.js';
|
|
7
7
|
/*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* the spacer is missing or the model already moved past what is mounted.
|
|
8
|
+
* Read from the spacer beta.6 puts above the mounted window, so a scroll frame copies those rows and not
|
|
9
|
+
* every visible one. The whole list stands in when the spacer is missing or the model moved past it.
|
|
11
10
|
*/
|
|
12
11
|
function mountedRows(model, shadow, elements) {
|
|
13
12
|
const spacer = shadow.querySelector('[data-file-tree-virtualized-sticky-offset]');
|
|
@@ -22,10 +21,7 @@ function mountedRows(model, shadow, elements) {
|
|
|
22
21
|
const paths = new Set(rows.map(row => row.path));
|
|
23
22
|
return elements.every(element => element.dataset.itemPath === undefined || paths.has(element.dataset.itemPath)) ? rows : visibleRows(model);
|
|
24
23
|
}
|
|
25
|
-
/*
|
|
26
|
-
* Lines the ports up with their rows: every size first, then the spaces they reserve, then every offset,
|
|
27
|
-
* then the ports, so a pass forces two layouts at most however many rows are mounted.
|
|
28
|
-
*/
|
|
24
|
+
/* Every size first, then the spaces, then every offset, then the ports, so a pass forces two layouts at most. */
|
|
29
25
|
export function positionPorts(ports, order = 'before-status') {
|
|
30
26
|
const spaced = [...ports].map(port => ({
|
|
31
27
|
port,
|
|
@@ -164,9 +160,9 @@ export function useFileTreeSlots(model, frame, label, {
|
|
|
164
160
|
dropIcon(port);
|
|
165
161
|
};
|
|
166
162
|
const clearPort = port_0 => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
163
|
+
for (const name of ['--adecore-tree-control-space', '--adecore-tree-decoration-space', '--adecore-tree-status-space']) {
|
|
164
|
+
port_0.rowElement.style.removeProperty(name);
|
|
165
|
+
}
|
|
170
166
|
delete port_0.rowElement.dataset.ownIcon;
|
|
171
167
|
dropPort(port_0);
|
|
172
168
|
};
|
package/dist/format/datetime.js
CHANGED
|
@@ -4,11 +4,8 @@ import { dateFormatter, wordFormatter } from './locale.js';
|
|
|
4
4
|
const WORD_PARTS = new Set(['month', 'weekday', 'dayPeriod', 'era']);
|
|
5
5
|
const toDate = at => typeof at === 'number' ? new Date(at) : at;
|
|
6
6
|
/*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* one to lift the word from, whatever order the two put them in: `19 Sep` in English against a Dutch
|
|
10
|
-
* region, `19 sep` once the interface is Dutch too, and a clock that reads `08:05` wherever the
|
|
11
|
-
* region does not say AM.
|
|
7
|
+
* The region's notation with the language's words: `19 Sep` in English against a Dutch region. Both
|
|
8
|
+
* formatters get the same options and instant, so every word part has one to lift, whatever the order.
|
|
12
9
|
*/
|
|
13
10
|
export const formatDateTime = (at, options) => {
|
|
14
11
|
const date = toDate(at);
|
|
@@ -69,14 +66,32 @@ const NUMERIC_DATE = {
|
|
|
69
66
|
month: 'numeric',
|
|
70
67
|
day: 'numeric'
|
|
71
68
|
};
|
|
69
|
+
const zonedSpecs = new WeakMap();
|
|
70
|
+
/* One options object per zone, so the formatter cached on it is built once (`dateFormatter`). */
|
|
71
|
+
const zoned = (options, timeZone) => {
|
|
72
|
+
if (timeZone === undefined) {
|
|
73
|
+
return options;
|
|
74
|
+
}
|
|
75
|
+
let byZone = zonedSpecs.get(options);
|
|
76
|
+
if (byZone === undefined) {
|
|
77
|
+
byZone = new Map();
|
|
78
|
+
zonedSpecs.set(options, byZone);
|
|
79
|
+
}
|
|
80
|
+
let spec = byZone.get(timeZone);
|
|
81
|
+
if (spec === undefined) {
|
|
82
|
+
spec = {
|
|
83
|
+
...options,
|
|
84
|
+
timeZone
|
|
85
|
+
};
|
|
86
|
+
byZone.set(timeZone, spec);
|
|
87
|
+
}
|
|
88
|
+
return spec;
|
|
89
|
+
};
|
|
72
90
|
/*
|
|
73
|
-
* `08:05`, or `08:05 AM` in a region that counts to twelve.
|
|
74
|
-
*
|
|
91
|
+
* `08:05`, or `08:05 AM` in a region that counts to twelve. A `timeZone` such as `UTC` writes a moment
|
|
92
|
+
* whose parts are given and mean the same wall clock anywhere.
|
|
75
93
|
*/
|
|
76
|
-
export const formatClock = (at, timeZone) => formatDateTime(at,
|
|
77
|
-
...CLOCK,
|
|
78
|
-
timeZone
|
|
79
|
-
});
|
|
94
|
+
export const formatClock = (at, timeZone) => formatDateTime(at, zoned(CLOCK, timeZone));
|
|
80
95
|
/* A time far enough off that its day is part of the answer: `Sat 08:05`. */
|
|
81
96
|
export const formatWeekdayClock = at => formatDateTime(at, WEEKDAY_CLOCK);
|
|
82
97
|
/* An hour of the day on its own, for the foot of a chart: `08`, or `8 AM` where that is the clock. */
|
|
@@ -84,30 +99,18 @@ export const formatHour = at => formatDateTime(at, HOUR);
|
|
|
84
99
|
/* The day of the week on its own, for the side of a grid by weekday: `Sat`, or `Saturday` when `long`. */
|
|
85
100
|
export const formatWeekday = (at, width = 'short') => formatDateTime(at, width === 'long' ? WEEKDAY_LONG : WEEKDAY);
|
|
86
101
|
/* `19 Sep`, the short date a row falls back to once "days ago" stops meaning anything. */
|
|
87
|
-
export const formatDay = (at, timeZone) => formatDateTime(at,
|
|
88
|
-
...DAY,
|
|
89
|
-
timeZone
|
|
90
|
-
});
|
|
102
|
+
export const formatDay = (at, timeZone) => formatDateTime(at, zoned(DAY, timeZone));
|
|
91
103
|
/* The same date with the year, for anything older than the one we are in. */
|
|
92
|
-
export const formatDayWithYear = (at, timeZone) => formatDateTime(at,
|
|
93
|
-
...DAY_WITH_YEAR,
|
|
94
|
-
timeZone
|
|
95
|
-
});
|
|
104
|
+
export const formatDayWithYear = (at, timeZone) => formatDateTime(at, zoned(DAY_WITH_YEAR, timeZone));
|
|
96
105
|
/* `Sat 19 Sep`. */
|
|
97
106
|
export const formatWeekdayDay = at => formatDateTime(at, WEEKDAY_DAY);
|
|
98
107
|
/* `19 Sep, 08:05`: a moment that is not today, to the minute. */
|
|
99
|
-
export const formatDayClock = (at, timeZone) => formatDateTime(at,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
});
|
|
103
|
-
/* `19 Sep 2026, 08:05`: the same moment with the year, for one that is not in the year we are in. */
|
|
104
|
-
export const formatDayClockWithYear = (at, timeZone) => formatDateTime(at, timeZone === undefined ? DAY_CLOCK_WITH_YEAR : {
|
|
105
|
-
...DAY_CLOCK_WITH_YEAR,
|
|
106
|
-
timeZone
|
|
107
|
-
});
|
|
108
|
+
export const formatDayClock = (at, timeZone) => formatDateTime(at, zoned(DAY_CLOCK, timeZone));
|
|
109
|
+
/* `19 Sep 2026, 08:05`: the same moment with the year. */
|
|
110
|
+
export const formatDayClockWithYear = (at, timeZone) => formatDateTime(at, zoned(DAY_CLOCK_WITH_YEAR, timeZone));
|
|
108
111
|
/* All numbers, as a form would print it: `19-9-2026` here, `9/19/2026` in the United States. */
|
|
109
112
|
export const formatNumericDate = at => formatDateTime(at, NUMERIC_DATE);
|
|
110
|
-
/*
|
|
113
|
+
/* In the zone of whoever is reading. */
|
|
111
114
|
export const isSameDay = (a, b) => {
|
|
112
115
|
const left = toDate(a);
|
|
113
116
|
const right = toDate(b);
|
package/dist/format/duration.js
CHANGED
|
@@ -4,11 +4,7 @@ const SECOND = 1000;
|
|
|
4
4
|
const MINUTE = 60 * SECOND;
|
|
5
5
|
const HOUR = 60 * MINUTE;
|
|
6
6
|
const DAY = 24 * HOUR;
|
|
7
|
-
/*
|
|
8
|
-
* How long something took, at the coarsest unit that still says something. The units are English
|
|
9
|
-
* abbreviations, the way the rest of the interface is written; only the number bends to the region,
|
|
10
|
-
* which is what `1,5 h` against `1.5 h` is about.
|
|
11
|
-
*/
|
|
7
|
+
/* At the coarsest unit that still says something. The units stay English; only the number bends to the region (`1,5 h`). */
|
|
12
8
|
export const formatDuration = ms => {
|
|
13
9
|
const seconds = Math.max(0, Math.round(ms / SECOND));
|
|
14
10
|
if (seconds < 60) {
|
|
@@ -54,11 +50,7 @@ export const formatCountdown = ms => {
|
|
|
54
50
|
}
|
|
55
51
|
return `${formatNumber(Math.max(1, Math.round(left / MINUTE)))}m`;
|
|
56
52
|
};
|
|
57
|
-
/*
|
|
58
|
-
* How long something has been running, to two units and no space to spare: `12s`, `2m 5s`, `3h 20m`.
|
|
59
|
-
* A call that took a fraction of a second still took some, so anything above zero reads as at least
|
|
60
|
-
* `1s`; only a clock that runs ahead of the start comes out as `0s`.
|
|
61
|
-
*/
|
|
53
|
+
/* `12s`, `2m 5s`, `3h 20m`. Anything above zero reads as at least `1s`; only a clock that runs ahead of the start comes out as `0s`. */
|
|
62
54
|
export const formatElapsedShort = ms => {
|
|
63
55
|
const seconds = ms <= 0 ? 0 : Math.max(1, Math.round(ms / SECOND));
|
|
64
56
|
if (seconds < 60) {
|
package/dist/format/locale.js
CHANGED
|
@@ -11,19 +11,16 @@ export const setFormatSource = next => {
|
|
|
11
11
|
source = next;
|
|
12
12
|
return previous;
|
|
13
13
|
};
|
|
14
|
-
/*
|
|
14
|
+
/* The country most of a language's speakers are in. */
|
|
15
15
|
const LANGUAGE_REGIONS = {
|
|
16
16
|
en: 'en-US',
|
|
17
17
|
nl: 'nl-NL'
|
|
18
18
|
};
|
|
19
|
-
/*
|
|
19
|
+
/* So a format never depends on which machine ran the test. */
|
|
20
20
|
export const FALLBACK_LOCALE = 'en-US';
|
|
21
|
-
/* A month and a weekday are words, so they come from the language the
|
|
22
|
-
order, the separators and the clock come from the region. English words in a Dutch notation is
|
|
23
|
-
what a Dutch Mac running an English app should read like, and both halves are a person's to set. */
|
|
21
|
+
/* A month and a weekday are words, so they come from the language; the order, the separators and the clock come from the region. */
|
|
24
22
|
export const wordLocale = () => source.language();
|
|
25
|
-
/*
|
|
26
|
-
formatter built on one it does not know throws where a number was meant to go. */
|
|
23
|
+
/* macOS hands out locales with overrides attached, and a formatter built on one `Intl` does not know throws. */
|
|
27
24
|
const usable = tag => {
|
|
28
25
|
if (tag === undefined || tag === '') {
|
|
29
26
|
return null;
|
|
@@ -35,10 +32,8 @@ const usable = tag => {
|
|
|
35
32
|
}
|
|
36
33
|
};
|
|
37
34
|
/*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* `en-US` and write `08:00 AM`; the shell reads the system's region instead and passes it in
|
|
41
|
-
* (`systemLocale`). A browser has no such thing, so there the language is the best there is.
|
|
35
|
+
* In a desktop shell Chromium's locale is the language of the app bundle, so an English bundle on a
|
|
36
|
+
* Dutch Mac would write `08:00 AM`; the shell passes the system's region in instead (`systemLocale`).
|
|
42
37
|
*/
|
|
43
38
|
export const systemLocale = () => {
|
|
44
39
|
const fromShell = usable(source.systemLocale?.());
|
|
@@ -50,11 +45,7 @@ export const systemLocale = () => {
|
|
|
50
45
|
}
|
|
51
46
|
return usable(navigator.languages?.[0] ?? navigator.language) ?? FALLBACK_LOCALE;
|
|
52
47
|
};
|
|
53
|
-
/*
|
|
54
|
-
* The region a language brings with it. The system's own when it already speaks that language, so
|
|
55
|
-
* Dutch in Belgium keeps writing dates the Belgian way, and the country the language is most spoken
|
|
56
|
-
* in when it does not.
|
|
57
|
-
*/
|
|
48
|
+
/* The system's own region when it already speaks the language, so Dutch in Belgium keeps writing dates the Belgian way. */
|
|
58
49
|
const regionOfLanguage = () => {
|
|
59
50
|
const language = source.language();
|
|
60
51
|
const system = systemLocale();
|
|
@@ -66,12 +57,10 @@ const resolve = region => {
|
|
|
66
57
|
}
|
|
67
58
|
return region === FORMAT_SYSTEM ? systemLocale() : region;
|
|
68
59
|
};
|
|
69
|
-
/*
|
|
70
|
-
plain function over the source rather than a hook. */
|
|
60
|
+
/* Read outside React as well, so it is a plain function rather than a hook. */
|
|
71
61
|
export const formatLocale = () => resolve(source.region());
|
|
72
62
|
const subscribe = onChange => source.subscribe(onChange);
|
|
73
|
-
/*
|
|
74
|
-
caller may use or ignore; subscribing is the point. */
|
|
63
|
+
/* Subscribing is the point: a component draws again once the region changes. */
|
|
75
64
|
export const useFormatLocale = () => {
|
|
76
65
|
return useSyncExternalStore(subscribe, formatLocale, formatLocale);
|
|
77
66
|
};
|
|
@@ -95,37 +84,28 @@ const relatives = new WeakMap();
|
|
|
95
84
|
const names = new WeakMap();
|
|
96
85
|
export const numberFormatter = options => cacheFor(numbers, options, formatLocale(), (locale, spec) => new Intl.NumberFormat(locale, spec));
|
|
97
86
|
export const dateFormatter = options => cacheFor(dates, options, formatLocale(), (locale, spec) => new Intl.DateTimeFormat(locale, spec));
|
|
98
|
-
/*
|
|
99
|
-
weekday, era and day period are lifted out of it. */
|
|
87
|
+
/* Never shown whole: only its month, weekday, era and day period are lifted out of it. */
|
|
100
88
|
export const wordFormatter = options => cacheFor(words, options, wordLocale(), (locale, spec) => new Intl.DateTimeFormat(locale, spec));
|
|
101
89
|
/* `3 min. geleden` is words as much as a number, so the language writes it, the way it writes a month. */
|
|
102
90
|
export const relativeFormatter = options => cacheFor(relatives, options, wordLocale(), (locale, spec) => new Intl.RelativeTimeFormat(locale, spec));
|
|
103
91
|
/* Proper names keep the runtime locale; a shared options object reuses its collator. */
|
|
104
92
|
export const nameCollator = options => cacheFor(names, options, undefined, (locale, spec) => new Intl.Collator(locale, spec));
|
|
105
93
|
const collators = new Map();
|
|
106
|
-
/*
|
|
107
|
-
* How two labels a person reads are put in order. Labels are words, so the language writes them and
|
|
108
|
-
* the language sorts them: Dutch puts Tekening after Terminal where English puts Drawing before it.
|
|
109
|
-
* Keyed on the locale rather than on an options object, since there are no options to key on.
|
|
110
|
-
*/
|
|
94
|
+
/* Labels are words, so the language sorts them: Dutch puts Tekening after Terminal where English puts Drawing before it. */
|
|
111
95
|
export const labelCollator = () => {
|
|
112
96
|
const locale = wordLocale();
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
|
|
97
|
+
let collator = collators.get(locale);
|
|
98
|
+
if (collator === undefined) {
|
|
99
|
+
collator = new Intl.Collator(locale, {
|
|
100
|
+
sensitivity: 'base',
|
|
101
|
+
numeric: true
|
|
102
|
+
});
|
|
103
|
+
collators.set(locale, collator);
|
|
116
104
|
}
|
|
117
|
-
const collator = new Intl.Collator(locale, {
|
|
118
|
-
sensitivity: 'base',
|
|
119
|
-
numeric: true
|
|
120
|
-
});
|
|
121
|
-
collators.set(locale, collator);
|
|
122
105
|
return collator;
|
|
123
106
|
};
|
|
124
107
|
let nameCollators = null;
|
|
125
|
-
/*
|
|
126
|
-
* The order of names that are no words, such as files: the runtime's own locale, numbers by value and
|
|
127
|
-
* case only to break a tie. It is what `localeCompare` did, which built a collator on every call.
|
|
128
|
-
*/
|
|
108
|
+
/* For names that are no words, such as files: what `localeCompare` did, without a collator built on every call. */
|
|
129
109
|
export const nameOrder = (left, right) => {
|
|
130
110
|
nameCollators ??= {
|
|
131
111
|
loose: new Intl.Collator(undefined, {
|
package/dist/format/number.js
CHANGED
|
@@ -7,7 +7,6 @@ const ONE_DECIMAL = {
|
|
|
7
7
|
};
|
|
8
8
|
/* A count as a region groups one: `1,234,567` there, `1.234.567` here. */
|
|
9
9
|
export const formatNumber = value => numberFormatter(WHOLE).format(Math.round(value));
|
|
10
|
-
/* The same, to one decimal, where the fraction is the part that means something. */
|
|
11
10
|
export const formatDecimal = value => numberFormatter(ONE_DECIMAL).format(value);
|
|
12
11
|
/* One options object per key, so the formatter cached on it is built once (`numberFormatter`). */
|
|
13
12
|
const specCache = build => {
|
|
@@ -36,9 +35,8 @@ export const formatRounded = (value, decimals) => numberFormatter(roundedSpec(de
|
|
|
36
35
|
const MAX_FRACTION_DIGITS = 100;
|
|
37
36
|
const NUMERAL = /^[+-]?\d+(?:\.(\d+))?$/;
|
|
38
37
|
/*
|
|
39
|
-
* A numeral as a database writes it (`12900`, `-0.50`, `9007199254740993`)
|
|
40
|
-
*
|
|
41
|
-
* Text that is no plain numeral, such as `NaN` or `1e999`, comes back as it is.
|
|
38
|
+
* A numeral as a database writes it (`12900`, `-0.50`, `9007199254740993`) with every digit kept: a
|
|
39
|
+
* decimal or a big integer arrives as text, and a float would round it. Anything else comes back as it is.
|
|
42
40
|
*/
|
|
43
41
|
export const formatNumeral = numeral => {
|
|
44
42
|
const text = typeof numeral === 'number' ? String(numeral) : numeral.trim();
|
|
@@ -52,20 +50,11 @@ export const formatNumeral = numeral => {
|
|
|
52
50
|
};
|
|
53
51
|
/* Percent as Activity Monitor writes it: a decimal under ten, where the difference still shows. */
|
|
54
52
|
export const formatPercent = value => `${value < 10 ? formatDecimal(value) : formatNumber(value)}%`;
|
|
55
|
-
/*
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const moneySpec = (currency, maximumFractionDigits) => {
|
|
61
|
-
const key = `${currency}|${maximumFractionDigits ?? ''}`;
|
|
62
|
-
const known = moneySpecs.get(key);
|
|
63
|
-
if (known !== undefined) {
|
|
64
|
-
return known;
|
|
65
|
-
}
|
|
66
|
-
// Narrow, or a Dutch region writes a dollar amount as `US$ 5.480,96`, which is a currency lesson
|
|
67
|
-
// nobody asked for in a table of prices.
|
|
68
|
-
const spec = {
|
|
53
|
+
/* Narrow, or a Dutch region writes a dollar amount as `US$ 5.480,96`. */
|
|
54
|
+
const moneySpec = specCache(key => {
|
|
55
|
+
const [currency, digits] = key.split('|');
|
|
56
|
+
const maximumFractionDigits = Number(digits);
|
|
57
|
+
return {
|
|
69
58
|
style: 'currency',
|
|
70
59
|
currency,
|
|
71
60
|
currencyDisplay: 'narrowSymbol',
|
|
@@ -73,11 +62,9 @@ const moneySpec = (currency, maximumFractionDigits) => {
|
|
|
73
62
|
maximumFractionDigits
|
|
74
63
|
} : {})
|
|
75
64
|
};
|
|
76
|
-
|
|
77
|
-
return spec;
|
|
78
|
-
};
|
|
65
|
+
});
|
|
79
66
|
/* An amount in the currency it is already in, as a bank statement would print it. */
|
|
80
|
-
export const formatMoney = (value, currency, maximumFractionDigits) => numberFormatter(moneySpec(currency
|
|
67
|
+
export const formatMoney = (value, currency, maximumFractionDigits) => numberFormatter(moneySpec(`${currency}|${maximumFractionDigits ?? ''}`)).format(value);
|
|
81
68
|
const SIGNIFICANT_MONEY = {
|
|
82
69
|
style: 'currency',
|
|
83
70
|
currency: 'USD',
|
package/dist/format/regions.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* The regions a person can read this app in, beside the one its language comes with and the one the
|
|
3
|
-
* operating system was set to. The list is short on purpose. It is here for a machine whose region
|
|
4
|
-
* reads nothing like the person in front of it, not as a country picker.
|
|
5
|
-
*/
|
|
6
1
|
export const FORMAT_LANGUAGE = 'language';
|
|
7
2
|
export const FORMAT_SYSTEM = 'system';
|
|
8
|
-
/*
|
|
9
|
-
|
|
3
|
+
/*
|
|
4
|
+
* Short on purpose: for a machine whose region reads nothing like the person in front of it, not a
|
|
5
|
+
* country picker. A country names itself through `Intl.DisplayNames`, so no translation file lists them.
|
|
6
|
+
*/
|
|
10
7
|
export const FORMAT_REGIONS = ['nl-NL', 'en-US', 'en-GB', 'de-DE', 'fr-FR', 'es-ES', 'sv-SE', 'ja-JP'];
|
|
11
8
|
export const FORMAT_REGION_CHOICES = [FORMAT_LANGUAGE, FORMAT_SYSTEM, ...FORMAT_REGIONS];
|
|
12
9
|
/* The country of a region tag, named in `language`: `nl-NL` in English is "Netherlands". */
|