efficient-shell 4.132.0 → 4.137.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/README.md +142 -18
- package/dist/{Browser-XPVJ2K7B.js → Browser-ZNX4WFUH.js} +13 -13
- package/dist/{Browser-XPVJ2K7B.js.map → Browser-ZNX4WFUH.js.map} +1 -1
- package/dist/{Calculator-ZXJPXG7F.js → Calculator-6FGNKOXU.js} +11 -11
- package/dist/{Calculator-ZXJPXG7F.js.map → Calculator-6FGNKOXU.js.map} +1 -1
- package/dist/ConfirmDialog-NPQMIGUR.js +4 -0
- package/dist/{ConfirmDialog-MTC7QMUJ.js.map → ConfirmDialog-NPQMIGUR.js.map} +1 -1
- package/dist/{CurrencyConverter-WSJ2BBSX.js → CurrencyConverter-FF7EXRYL.js} +11 -11
- package/dist/{CurrencyConverter-WSJ2BBSX.js.map → CurrencyConverter-FF7EXRYL.js.map} +1 -1
- package/dist/{Documents-ONGSXUJI.js → Documents-H3R7XSBH.js} +13 -13
- package/dist/{Documents-ONGSXUJI.js.map → Documents-H3R7XSBH.js.map} +1 -1
- package/dist/{Files-GQZMFWXQ.js → Files-ZHJIAUC2.js} +19 -19
- package/dist/{Files-GQZMFWXQ.js.map → Files-ZHJIAUC2.js.map} +1 -1
- package/dist/{Notepad-HM73XAM4.js → Notepad-VE7ISWRQ.js} +14 -14
- package/dist/{Notepad-HM73XAM4.js.map → Notepad-VE7ISWRQ.js.map} +1 -1
- package/dist/PdfViewer-SQBFYAGW.js +5 -0
- package/dist/{PdfViewer-M2YGZIYX.js.map → PdfViewer-SQBFYAGW.js.map} +1 -1
- package/dist/{PomodoroTimer-DG3LI5CX.js → PomodoroTimer-IR3WREED.js} +13 -13
- package/dist/{PomodoroTimer-DG3LI5CX.js.map → PomodoroTimer-IR3WREED.js.map} +1 -1
- package/dist/{Preview-TUSV4UMO.js → Preview-DAQGRNRM.js} +16 -16
- package/dist/{Preview-TUSV4UMO.js.map → Preview-DAQGRNRM.js.map} +1 -1
- package/dist/{Sidebar-BPU7RCZP.js → Sidebar-YW6H4NDJ.js} +3 -3
- package/dist/{Sidebar-BPU7RCZP.js.map → Sidebar-YW6H4NDJ.js.map} +1 -1
- package/dist/{Spreadsheet-3WTXCHYQ.js → Spreadsheet-HOCPHJOC.js} +14 -14
- package/dist/{Spreadsheet-3WTXCHYQ.js.map → Spreadsheet-HOCPHJOC.js.map} +1 -1
- package/dist/{Stock-YMPOMUAW.js → Stock-LVRQPURG.js} +11 -11
- package/dist/{Stock-YMPOMUAW.js.map → Stock-LVRQPURG.js.map} +1 -1
- package/dist/{Weather-NZO3CWLH.js → Weather-LZQGVDJL.js} +11 -11
- package/dist/{Weather-NZO3CWLH.js.map → Weather-LZQGVDJL.js.map} +1 -1
- package/dist/{WorldClock-HUC6D3AD.js → WorldClock-XPD7WOZT.js} +11 -11
- package/dist/{WorldClock-HUC6D3AD.js.map → WorldClock-XPD7WOZT.js.map} +1 -1
- package/dist/apps/index.d.ts +2 -2
- package/dist/apps/index.js +30 -30
- package/dist/apps/index.js.map +1 -1
- package/dist/brand.css +1 -1
- package/dist/{chunk-CT3HVZRZ.js → chunk-5O42JXQE.js} +2 -2
- package/dist/chunk-5O42JXQE.js.map +1 -0
- package/dist/{chunk-CGXMWHQW.js → chunk-5RPTS3BT.js} +3 -3
- package/dist/{chunk-CGXMWHQW.js.map → chunk-5RPTS3BT.js.map} +1 -1
- package/dist/{chunk-D276EMXS.js → chunk-6XJEJWNJ.js} +7 -3
- package/dist/chunk-6XJEJWNJ.js.map +1 -0
- package/dist/{chunk-I464GYJJ.js → chunk-BE7FZOFU.js} +2 -2
- package/dist/chunk-BE7FZOFU.js.map +1 -0
- package/dist/{chunk-CJYO4RVV.js → chunk-COWYSHG2.js} +5 -5
- package/dist/chunk-COWYSHG2.js.map +1 -0
- package/dist/{chunk-3L463T5H.js → chunk-DVZWYWSD.js} +2 -2
- package/dist/chunk-DVZWYWSD.js.map +1 -0
- package/dist/{chunk-MQPX6ERJ.js → chunk-E7TB6WD2.js} +4 -4
- package/dist/{chunk-MQPX6ERJ.js.map → chunk-E7TB6WD2.js.map} +1 -1
- package/dist/{chunk-SEWF4O3H.js → chunk-FIHOGVUP.js} +3 -3
- package/dist/chunk-FIHOGVUP.js.map +1 -0
- package/dist/{chunk-TQURTLK2.js → chunk-HUBJAUGG.js} +5 -5
- package/dist/{chunk-TQURTLK2.js.map → chunk-HUBJAUGG.js.map} +1 -1
- package/dist/{chunk-XH3ELPQZ.js → chunk-I2TAAJHS.js} +3 -3
- package/dist/chunk-I2TAAJHS.js.map +1 -0
- package/dist/{chunk-ZKHD4J73.js → chunk-ICTRCKUE.js} +10 -10
- package/dist/chunk-ICTRCKUE.js.map +1 -0
- package/dist/{chunk-E3TWIN7Z.js → chunk-JOPU6WPY.js} +7 -6
- package/dist/chunk-JOPU6WPY.js.map +1 -0
- package/dist/{chunk-7MA5XBWD.js → chunk-PVPPAWVM.js} +5 -5
- package/dist/{chunk-7MA5XBWD.js.map → chunk-PVPPAWVM.js.map} +1 -1
- package/dist/{chunk-FONEQRBH.js → chunk-R7QGMK6N.js} +3 -3
- package/dist/{chunk-FONEQRBH.js.map → chunk-R7QGMK6N.js.map} +1 -1
- package/dist/{chunk-LQTVTOSY.js → chunk-RT6DSB5Y.js} +45 -19
- package/dist/chunk-RT6DSB5Y.js.map +1 -0
- package/dist/{chunk-BFBWLCO6.js → chunk-TW7LPMVR.js} +2 -2
- package/dist/chunk-TW7LPMVR.js.map +1 -0
- package/dist/{chunk-EENVXIVU.js → chunk-UTYKLGGT.js} +3 -3
- package/dist/{chunk-EENVXIVU.js.map → chunk-UTYKLGGT.js.map} +1 -1
- package/dist/{chunk-KWEX4ZAF.js → chunk-VNJJCH5A.js} +3 -3
- package/dist/{chunk-KWEX4ZAF.js.map → chunk-VNJJCH5A.js.map} +1 -1
- package/dist/{chunk-TFXJRHJV.js → chunk-XJHZWSKV.js} +3 -3
- package/dist/{chunk-TFXJRHJV.js.map → chunk-XJHZWSKV.js.map} +1 -1
- package/dist/{chunk-VWZIGZFF.js → chunk-Y3GYJ7YR.js} +4 -4
- package/dist/{chunk-VWZIGZFF.js.map → chunk-Y3GYJ7YR.js.map} +1 -1
- package/dist/{chunk-BJ34QOR3.js → chunk-YA4EE7ST.js} +842 -272
- package/dist/chunk-YA4EE7ST.js.map +1 -0
- package/dist/{chunk-CLGNTGC5.js → chunk-YDHXWCCJ.js} +3 -3
- package/dist/{chunk-CLGNTGC5.js.map → chunk-YDHXWCCJ.js.map} +1 -1
- package/dist/{chunk-7IN7YZAL.js → chunk-YE6GUDGP.js} +4 -3
- package/dist/chunk-YE6GUDGP.js.map +1 -0
- package/dist/chunk-ZS7PMGUW.js +7 -0
- package/dist/{chunk-JMKYYPOF.js.map → chunk-ZS7PMGUW.js.map} +1 -1
- package/dist/file-intake/index.js +2 -2
- package/dist/{index-COwksV6G.d.ts → index-DVI9DMSu.d.ts} +383 -20
- package/dist/index.d.ts +3 -3
- package/dist/index.js +39 -39
- package/dist/index.js.map +1 -1
- package/dist/map/index.js +1 -1
- package/dist/markdown/index.d.ts +4 -4
- package/dist/markdown/index.js.map +1 -1
- package/dist/markup/index.d.ts +2 -2
- package/dist/markup/index.js.map +1 -1
- package/dist/page-tabs/index.js +5 -5
- package/dist/shell.css +1 -1
- package/dist/styles.css +4 -4
- package/dist/themes.css +3 -3
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +14 -14
- package/dist/ui.css +311 -18
- package/package.json +1 -1
- package/dist/ConfirmDialog-MTC7QMUJ.js +0 -4
- package/dist/PdfViewer-M2YGZIYX.js +0 -5
- package/dist/chunk-3L463T5H.js.map +0 -1
- package/dist/chunk-7IN7YZAL.js.map +0 -1
- package/dist/chunk-BFBWLCO6.js.map +0 -1
- package/dist/chunk-BJ34QOR3.js.map +0 -1
- package/dist/chunk-CJYO4RVV.js.map +0 -1
- package/dist/chunk-CT3HVZRZ.js.map +0 -1
- package/dist/chunk-D276EMXS.js.map +0 -1
- package/dist/chunk-E3TWIN7Z.js.map +0 -1
- package/dist/chunk-I464GYJJ.js.map +0 -1
- package/dist/chunk-JMKYYPOF.js +0 -7
- package/dist/chunk-LQTVTOSY.js.map +0 -1
- package/dist/chunk-SEWF4O3H.js.map +0 -1
- package/dist/chunk-XH3ELPQZ.js.map +0 -1
- package/dist/chunk-ZKHD4J73.js.map +0 -1
package/dist/ui.css
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* efficient-shell/ui.css — styles for the UI kit, without the window chrome.
|
|
3
3
|
*
|
|
4
|
-
* Import this when you take `
|
|
4
|
+
* Import this when you take `efficient-shell/ui`:
|
|
5
5
|
*
|
|
6
|
-
* import "
|
|
6
|
+
* import "efficient-shell/ui.css";
|
|
7
7
|
*
|
|
8
|
-
* Import EXACTLY ONE of this and `
|
|
8
|
+
* Import EXACTLY ONE of this and `efficient-shell/styles.css` — the latter is
|
|
9
9
|
* the umbrella over this file plus shell.css, so taking both doubles every rule.
|
|
10
10
|
*
|
|
11
11
|
* You supply Tailwind v4 yourself (`@import "tailwindcss"` in your own entry,
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
|
|
89
89
|
/* Tailwind v4 doesn't scan node_modules by default — tell it to scan this
|
|
90
90
|
package's compiled JS so utility classes used in kit components get
|
|
91
|
-
generated when consumers import
|
|
91
|
+
generated when consumers import efficient-shell/ui.css. */
|
|
92
92
|
@source "./**/*.js";
|
|
93
93
|
|
|
94
94
|
/* Tailwind scans every text file it can reach, prose included, so a class
|
|
@@ -153,7 +153,7 @@ html.rosh-reduce-transparency *::after {
|
|
|
153
153
|
* `[data-theme="dark"]` scope read any of these twelve. It exists so a surface
|
|
154
154
|
* built WITHOUT the kit's utility classes — a report, an emailed document, a
|
|
155
155
|
* standalone page — can read the same roles the portals do. That surface is
|
|
156
|
-
* governed by harness 52-brand-surface.md and loads `
|
|
156
|
+
* governed by harness 52-brand-surface.md and loads `efficient-shell/brand.css`.
|
|
157
157
|
*
|
|
158
158
|
* They are load-bearing in light now: the timeline card is drawn from them in
|
|
159
159
|
* both themes, and the frosted glass is tinted from `--surface` (through
|
|
@@ -210,17 +210,16 @@ html.rosh-reduce-transparency *::after {
|
|
|
210
210
|
is what `.text-gray-500` renders as in dark, so it carries real text. */
|
|
211
211
|
--ink-faint: #848aa2;
|
|
212
212
|
/*
|
|
213
|
-
*
|
|
213
|
+
* Read directly by `PopupMenuLabel`, the section labels in every menu —
|
|
214
|
+
* 5.8:1 on `--surface`, and held to 4.5:1 on the frosted glass by
|
|
215
|
+
* tests/menuLabelContrast. Lower it and that spec says where it stops
|
|
216
|
+
* reading.
|
|
214
217
|
*
|
|
215
|
-
*
|
|
216
|
-
* to `--ink` so short taskbar-button
|
|
217
|
-
* That override is global by design —
|
|
218
|
-
* bare utility selector cannot live
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* Left declared rather than deleted: it names a real rung, and a consumer
|
|
222
|
-
* scoping its own `.text-gray-600` rule can reach it. Deleting it would be a
|
|
223
|
-
* rendering change, which this release deliberately is not.
|
|
218
|
+
* NOT what `.text-gray-600` renders, though `.text-gray-600` below reads it:
|
|
219
|
+
* a later rule overrides that utility to `--ink` so short taskbar-button
|
|
220
|
+
* labels stay readable on dark glass. That override is global by design —
|
|
221
|
+
* shell.css's docblock spells out why a bare utility selector cannot live
|
|
222
|
+
* there — so `text-gray-600` renders `--ink` everywhere.
|
|
224
223
|
*/
|
|
225
224
|
--ink-muted: #9399b2;
|
|
226
225
|
--ink: #a6adc8;
|
|
@@ -580,7 +579,7 @@ html.rosh-reduce-transparency *::after {
|
|
|
580
579
|
/* ── Kit colours ────────────────────────────────────────────────────────────
|
|
581
580
|
* Every colour a kit component used to write as a literal in its TypeScript,
|
|
582
581
|
* as a token a host can reach. `tests/kitColourLiterals.test.ts` walks
|
|
583
|
-
* everything `
|
|
582
|
+
* everything `efficient-shell/ui` reaches and fails on a hex, `rgb()`, `hsl()` or
|
|
584
583
|
* any other colour function written into a string; the allow-list beside it
|
|
585
584
|
* names the few literals that are data rather than chrome.
|
|
586
585
|
*
|
|
@@ -659,6 +658,75 @@ html.rosh-reduce-transparency *::after {
|
|
|
659
658
|
--rosh-glass-solid-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
|
|
660
659
|
}
|
|
661
660
|
|
|
661
|
+
/* ── Tooltip arrow ──────────────────────────────────────────────────────────
|
|
662
|
+
* `Tooltip`'s pointer: a 10px square turned 45°, standing out of the bubble's
|
|
663
|
+
* edge that faces the trigger. `data-side` is the side the BUBBLE is on, so
|
|
664
|
+
* `top` means the bubble is above its trigger and the arrow points down.
|
|
665
|
+
*
|
|
666
|
+
* It is the bubble's own surface. `Tooltip` fills it inline with `glassFill()`
|
|
667
|
+
* — the glass as one flat colour: exactly the bubble's opaque surface under
|
|
668
|
+
* `rosh-reduce-transparency`, the surface at the glass's own alpha when
|
|
669
|
+
* frosted (why not the gradient or a blur of its own: `glassFill` in
|
|
670
|
+
* utils/glass.ts) — and gives it the bubble's border as `--rosh-tooltip-edge`.
|
|
671
|
+
* So it is solid or frosted with the bubble, light or dark with it, and follows
|
|
672
|
+
* whatever a theme or a host does to `--rosh-glass-*` and `--surface`: no
|
|
673
|
+
* colour is written here.
|
|
674
|
+
*
|
|
675
|
+
* Where it meets the bubble, two decisions:
|
|
676
|
+
* * It is CLIPPED to its outward half. A frosted bubble is translucent, and
|
|
677
|
+
* the inner half of a whole square laid over it would show through as a
|
|
678
|
+
* darker diamond inside the bubble.
|
|
679
|
+
* * Its centre — the clip line — sits on the INNER line of the bubble's 1px
|
|
680
|
+
* border, so the outward half covers that border where the two meet, and
|
|
681
|
+
* the border runs round bubble and arrow together: drawn on the arrow's two
|
|
682
|
+
* outward edges only. On a solid bubble the join is invisible; on a frosted
|
|
683
|
+
* one the hairline under the base shows through faintly, as anything
|
|
684
|
+
* behind translucent glass does.
|
|
685
|
+
*
|
|
686
|
+
* Placed: `Tooltip` writes `left`/`top` as the point on the bubble's outer edge
|
|
687
|
+
* the arrow is centred on, and each side's margins move the square's centre
|
|
688
|
+
* from there to 1px inside it. Unmeasured (a server render, jsdom), the same
|
|
689
|
+
* point is where `SIDE_POS` puts the bubble's edge: centred on the trigger,
|
|
690
|
+
* 0.75rem out. The tip is rounded (2px) like the bubble's corners; the other
|
|
691
|
+
* corners are cut off by the clip. */
|
|
692
|
+
.rosh-tooltip-arrow {
|
|
693
|
+
position: absolute;
|
|
694
|
+
z-index: 300;
|
|
695
|
+
box-sizing: border-box;
|
|
696
|
+
width: 10px;
|
|
697
|
+
height: 10px;
|
|
698
|
+
pointer-events: none;
|
|
699
|
+
transform: rotate(45deg);
|
|
700
|
+
}
|
|
701
|
+
.rosh-tooltip-arrow[data-side="top"] {
|
|
702
|
+
left: 50%; top: -0.75rem; margin: -6px 0 0 -5px;
|
|
703
|
+
clip-path: polygon(100% 0, 100% 100%, 0 100%);
|
|
704
|
+
border-right: var(--rosh-tooltip-edge, 1px solid var(--rosh-glass-border));
|
|
705
|
+
border-bottom: var(--rosh-tooltip-edge, 1px solid var(--rosh-glass-border));
|
|
706
|
+
border-bottom-right-radius: 2px;
|
|
707
|
+
}
|
|
708
|
+
.rosh-tooltip-arrow[data-side="bottom"] {
|
|
709
|
+
left: 50%; top: calc(100% + 0.75rem); margin: -4px 0 0 -5px;
|
|
710
|
+
clip-path: polygon(0 0, 100% 0, 0 100%);
|
|
711
|
+
border-top: var(--rosh-tooltip-edge, 1px solid var(--rosh-glass-border));
|
|
712
|
+
border-left: var(--rosh-tooltip-edge, 1px solid var(--rosh-glass-border));
|
|
713
|
+
border-top-left-radius: 2px;
|
|
714
|
+
}
|
|
715
|
+
.rosh-tooltip-arrow[data-side="left"] {
|
|
716
|
+
left: -0.75rem; top: 50%; margin: -5px 0 0 -6px;
|
|
717
|
+
clip-path: polygon(0 0, 100% 0, 100% 100%);
|
|
718
|
+
border-top: var(--rosh-tooltip-edge, 1px solid var(--rosh-glass-border));
|
|
719
|
+
border-right: var(--rosh-tooltip-edge, 1px solid var(--rosh-glass-border));
|
|
720
|
+
border-top-right-radius: 2px;
|
|
721
|
+
}
|
|
722
|
+
.rosh-tooltip-arrow[data-side="right"] {
|
|
723
|
+
left: calc(100% + 0.75rem); top: 50%; margin: -5px 0 0 -4px;
|
|
724
|
+
clip-path: polygon(0 0, 100% 100%, 0 100%);
|
|
725
|
+
border-left: var(--rosh-tooltip-edge, 1px solid var(--rosh-glass-border));
|
|
726
|
+
border-bottom: var(--rosh-tooltip-edge, 1px solid var(--rosh-glass-border));
|
|
727
|
+
border-bottom-left-radius: 2px;
|
|
728
|
+
}
|
|
729
|
+
|
|
662
730
|
/* ── Budget overrun hatch ───────────────────────────────────────────────────
|
|
663
731
|
* `BudgetBar`'s third drawing. A run past its wall clock must not be pictured
|
|
664
732
|
* as a full bar: a full solid bar is the calm "finished" shape, and this is the
|
|
@@ -681,6 +749,231 @@ html.rosh-reduce-transparency *::after {
|
|
|
681
749
|
);
|
|
682
750
|
}
|
|
683
751
|
|
|
752
|
+
/* ── DataTable on a narrow container ───────────────────────────────────────
|
|
753
|
+
* `<DataTable stackOnNarrow>`. Below 40rem of the TABLE'S OWN width every row
|
|
754
|
+
* is drawn as a card: one line per cell, the column's name on the left in the
|
|
755
|
+
* header's small uppercase voice, the value beside it. At 375px a strip of six
|
|
756
|
+
* columns wraps every cell onto two or three lines and pushes the last columns
|
|
757
|
+
* off the edge; a card gives each value the width there is.
|
|
758
|
+
*
|
|
759
|
+
* A CONTAINER query, not a media query. A table in a sidebar or a split pane
|
|
760
|
+
* on a wide monitor is as narrow as one on a phone, and only the container
|
|
761
|
+
* knows it. The wrapper (`rosh-dt-stack`) is the container, named so a table
|
|
762
|
+
* inside another container — a card that is one itself — answers to its own.
|
|
763
|
+
* 40rem rather than 640px so it moves with the reader's text size, as the
|
|
764
|
+
* columns it is making room for do. A container condition cannot read a custom
|
|
765
|
+
* property, which is why the width is not a token: one per table would mean a
|
|
766
|
+
* copy of every rule below for each.
|
|
767
|
+
*
|
|
768
|
+
* NOTHING HERE IS A DARK RULE. Every colour reads the neutral ramp, which the
|
|
769
|
+
* dark theme swaps underneath, so both themes are one set of rules.
|
|
770
|
+
*
|
|
771
|
+
* Why some declarations carry `!important`, and only those:
|
|
772
|
+
* - three are inline styles the component writes for the wide layout — a
|
|
773
|
+
* header's `width`, a pinned column's `left`, the table's `minWidth` —
|
|
774
|
+
* and an inline style beats any rule that is not important;
|
|
775
|
+
* - the rest are colours the dark remaps also set with `!important`
|
|
776
|
+
* (`.bg-white`, `.bg-gray-50`, `.border-gray-100` on the row). Those
|
|
777
|
+
* selectors weigh (0,2,0), so the rules that must beat them are written
|
|
778
|
+
* from `.rosh-dt-table` down to weigh more.
|
|
779
|
+
* Everything else is unlayered, which already beats the Tailwind utilities the
|
|
780
|
+
* wide layout is drawn with (they live in `@layer utilities`). A caller's row
|
|
781
|
+
* TINT survives: the card sets no background, so `rowClassName="bg-red-50"`
|
|
782
|
+
* still paints it. Its borders and spacing are the card's.
|
|
783
|
+
*
|
|
784
|
+
* The label is `::before { content: attr(data-label) }` with an EMPTY
|
|
785
|
+
* alternative text (`/ ""`). Generated content is otherwise part of a cell's
|
|
786
|
+
* accessible name, so a screen reader would hear "Qty, Qty 5": once from the
|
|
787
|
+
* column header it announces with every cell, once from the label. The first
|
|
788
|
+
* `content` is the fallback for an engine that cannot parse the second.
|
|
789
|
+
*
|
|
790
|
+
* Outside the query, `rosh-dt-value` is `display: contents`: the box the value
|
|
791
|
+
* is wrapped in so a card line is always two items however many nodes `render`
|
|
792
|
+
* returns, and in the wide layout no box at all.
|
|
793
|
+
*/
|
|
794
|
+
.rosh-dt-stack {
|
|
795
|
+
container: rosh-dt / inline-size;
|
|
796
|
+
}
|
|
797
|
+
.rosh-dt-value {
|
|
798
|
+
display: contents;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
@container rosh-dt (width < 40rem) {
|
|
802
|
+
/* The frame `bordered` draws steps aside: every card has an edge of its own,
|
|
803
|
+
and a frame around cards is a second border around each of them. */
|
|
804
|
+
.rosh-dt-scroll {
|
|
805
|
+
border-width: 0;
|
|
806
|
+
border-radius: 0;
|
|
807
|
+
}
|
|
808
|
+
.rosh-dt-table {
|
|
809
|
+
display: block;
|
|
810
|
+
min-width: 0 !important;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/* The header stays, compact. Sorting has to remain reachable, and it is
|
|
814
|
+
these buttons — with their arrows and their `aria-sort` — that do it, so
|
|
815
|
+
the sortable headers become a wrapping row of chips above the cards, and
|
|
816
|
+
"select all" leads it, above the column of boxes it controls. */
|
|
817
|
+
/* A grouped table has two header rows — "select all" in the first, the
|
|
818
|
+
grouped columns' chips in the second — so the rows sit side by side as
|
|
819
|
+
well as their chips, and the strip reads as one line wherever it fits.
|
|
820
|
+
Spacing is each chip's margin, not a gap, so a row left with nothing to
|
|
821
|
+
show takes no room at all. */
|
|
822
|
+
.rosh-dt-head {
|
|
823
|
+
display: flex;
|
|
824
|
+
flex-wrap: wrap;
|
|
825
|
+
align-items: center;
|
|
826
|
+
}
|
|
827
|
+
.rosh-dt-table > .rosh-dt-head > tr {
|
|
828
|
+
display: flex;
|
|
829
|
+
flex-wrap: wrap;
|
|
830
|
+
align-items: center;
|
|
831
|
+
border-width: 0;
|
|
832
|
+
background-color: transparent !important;
|
|
833
|
+
}
|
|
834
|
+
.rosh-dt-head th.rosh-dt-sort {
|
|
835
|
+
position: static;
|
|
836
|
+
width: auto !important;
|
|
837
|
+
margin: 0 0.375rem 0.5rem 0;
|
|
838
|
+
padding: 0;
|
|
839
|
+
border: 1px solid var(--line);
|
|
840
|
+
border-radius: var(--radius-md, 0.375rem);
|
|
841
|
+
/* The wide header's own fill, which is what the dark remap already gives
|
|
842
|
+
a pinned header — so neither theme needs to fight it. */
|
|
843
|
+
background-color: var(--surface-sunken);
|
|
844
|
+
}
|
|
845
|
+
.rosh-dt-head th.rosh-dt-sort[aria-sort="ascending"],
|
|
846
|
+
.rosh-dt-head th.rosh-dt-sort[aria-sort="descending"] {
|
|
847
|
+
border-color: var(--line-strong);
|
|
848
|
+
}
|
|
849
|
+
/* The button fills its chip, so the whole chip is the target — 32px tall,
|
|
850
|
+
past WCAG 2.5.8's 24. */
|
|
851
|
+
.rosh-dt-sort > button {
|
|
852
|
+
min-height: 2rem;
|
|
853
|
+
padding: 0.375rem 0.625rem;
|
|
854
|
+
}
|
|
855
|
+
/* A chip names its column group too: two chips both reading "Amount" would
|
|
856
|
+
leave the reader to guess which one sorts the debits. Hidden from the
|
|
857
|
+
accessibility tree like the card labels — the group header is still a
|
|
858
|
+
header, and is read with it. */
|
|
859
|
+
.rosh-dt-sort > button[data-group]::before {
|
|
860
|
+
content: attr(data-group) "\a0\b7\a0";
|
|
861
|
+
content: attr(data-group) "\a0\b7\a0" / "";
|
|
862
|
+
}
|
|
863
|
+
.rosh-dt-table > .rosh-dt-head > tr > th.rosh-dt-select {
|
|
864
|
+
position: static;
|
|
865
|
+
width: auto !important;
|
|
866
|
+
margin: 0 0.375rem 0.5rem 0;
|
|
867
|
+
/* Level with the card checkboxes below: a card's 1px edge, then its
|
|
868
|
+
padding. */
|
|
869
|
+
padding: 0.25rem 0.5rem 0.25rem calc(0.75rem + 1px);
|
|
870
|
+
background-color: transparent !important;
|
|
871
|
+
}
|
|
872
|
+
/* Every other header — a column that does not sort, a group — leaves the
|
|
873
|
+
screen but not the table: a screen reader still finds each cell's column
|
|
874
|
+
header. `left` is reset because a pinned header carries an inline offset,
|
|
875
|
+
and a 1px box parked 400px to the right is horizontal overflow. */
|
|
876
|
+
.rosh-dt-head th:not(.rosh-dt-sort, .rosh-dt-select) {
|
|
877
|
+
position: absolute;
|
|
878
|
+
top: 0 !important;
|
|
879
|
+
left: 0 !important;
|
|
880
|
+
width: 1px !important;
|
|
881
|
+
height: 1px;
|
|
882
|
+
margin: -1px;
|
|
883
|
+
padding: 0;
|
|
884
|
+
overflow: hidden;
|
|
885
|
+
clip-path: inset(50%);
|
|
886
|
+
white-space: nowrap;
|
|
887
|
+
border-width: 0;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/* One card per row. */
|
|
891
|
+
.rosh-dt-body {
|
|
892
|
+
display: grid;
|
|
893
|
+
gap: 0.5rem;
|
|
894
|
+
}
|
|
895
|
+
.rosh-dt-table > .rosh-dt-body > .rosh-dt-row {
|
|
896
|
+
display: block;
|
|
897
|
+
position: relative;
|
|
898
|
+
padding: 0.25rem 0.75rem;
|
|
899
|
+
border: 1px solid var(--line) !important;
|
|
900
|
+
border-radius: var(--radius-lg, 0.5rem);
|
|
901
|
+
}
|
|
902
|
+
/* The checkbox sits in the card's top-left corner, level with the first
|
|
903
|
+
line, rather than spending a line of its own. */
|
|
904
|
+
.rosh-dt-table > .rosh-dt-body > .rosh-dt-row-select {
|
|
905
|
+
padding-left: 2.5rem;
|
|
906
|
+
}
|
|
907
|
+
.rosh-dt-table > .rosh-dt-body > .rosh-dt-row > td.rosh-dt-select {
|
|
908
|
+
position: absolute;
|
|
909
|
+
top: 0;
|
|
910
|
+
left: 0 !important;
|
|
911
|
+
display: flex;
|
|
912
|
+
width: auto !important;
|
|
913
|
+
padding: 0.75rem;
|
|
914
|
+
background-color: transparent !important;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/* One line per cell: the label, then the value. A pinned cell's background
|
|
918
|
+
was there to hide the columns scrolling under it; there are none. */
|
|
919
|
+
.rosh-dt-table > .rosh-dt-body > .rosh-dt-row > td.rosh-dt-cell {
|
|
920
|
+
display: block;
|
|
921
|
+
position: static;
|
|
922
|
+
max-width: none;
|
|
923
|
+
padding: 0.375rem 0;
|
|
924
|
+
background-color: transparent !important;
|
|
925
|
+
}
|
|
926
|
+
.rosh-dt-cell + .rosh-dt-cell {
|
|
927
|
+
border-top: 1px solid var(--line-subtle);
|
|
928
|
+
}
|
|
929
|
+
.rosh-dt-table > .rosh-dt-body > .rosh-dt-row > td.rosh-dt-cell[data-label] {
|
|
930
|
+
display: grid;
|
|
931
|
+
grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
|
|
932
|
+
column-gap: 0.75rem;
|
|
933
|
+
align-items: baseline;
|
|
934
|
+
}
|
|
935
|
+
.rosh-dt-cell[data-label]::before {
|
|
936
|
+
content: attr(data-label);
|
|
937
|
+
content: attr(data-label) / "";
|
|
938
|
+
font-size: 0.75rem;
|
|
939
|
+
line-height: 1rem;
|
|
940
|
+
font-weight: 600;
|
|
941
|
+
letter-spacing: 0.025em;
|
|
942
|
+
text-transform: uppercase;
|
|
943
|
+
/* Left whatever the column's alignment: that is the VALUE's. And free to
|
|
944
|
+
wrap in an `ellipsis` column, whose cell is `nowrap` for the value. */
|
|
945
|
+
text-align: start;
|
|
946
|
+
white-space: normal;
|
|
947
|
+
color: var(--ink-faint);
|
|
948
|
+
overflow-wrap: anywhere;
|
|
949
|
+
}
|
|
950
|
+
/* The value keeps the cell's alignment, so a figures column still lines its
|
|
951
|
+
decimal points up at the card's right edge. A long token — an email, a
|
|
952
|
+
part number — breaks rather than pushing the card wider than the screen. */
|
|
953
|
+
.rosh-dt-cell > .rosh-dt-value {
|
|
954
|
+
display: block;
|
|
955
|
+
min-width: 0;
|
|
956
|
+
overflow-wrap: anywhere;
|
|
957
|
+
}
|
|
958
|
+
/* `ellipsis` keeps its promise of one line; the cell is a grid now, and
|
|
959
|
+
only the value can carry the ellipsis. */
|
|
960
|
+
.rosh-dt-clip > .rosh-dt-value {
|
|
961
|
+
overflow: hidden;
|
|
962
|
+
text-overflow: ellipsis;
|
|
963
|
+
white-space: nowrap;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
.rosh-dt-body > .rosh-dt-empty,
|
|
967
|
+
.rosh-dt-body > .rosh-dt-empty > td {
|
|
968
|
+
display: block;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
/* The pager wraps rather than running off a narrow screen. */
|
|
972
|
+
.rosh-dt-pager > nav {
|
|
973
|
+
flex-wrap: wrap;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
684
977
|
/* ── Chart motion ───────────────────────────────────────────────────────────
|
|
685
978
|
* Every animation the chart family uses, as classes, so no chart implements
|
|
686
979
|
* motion itself and none of them can forget the reduced-motion rule below.
|
|
@@ -1724,7 +2017,7 @@ html.rosh-reduce-transparency *::after {
|
|
|
1724
2017
|
:is([data-theme="dark"], .dark) .text-black { color: var(--ink-strongest) !important; }
|
|
1725
2018
|
:is([data-theme="dark"], .dark) .hover\:text-black:hover { color: #ffffff !important; }
|
|
1726
2019
|
|
|
1727
|
-
/* Markdown — the clamped note (
|
|
2020
|
+
/* Markdown — the clamped note (efficient-shell/markdown, `clamp`).
|
|
1728
2021
|
|
|
1729
2022
|
The fade MASKS the text rather than laying a coloured gradient over it. A
|
|
1730
2023
|
gradient has to know what colour to fade to, and there is no answer that
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/_previewStage.ts"],"names":[],"mappings":";AA+CO,IAAM,wBAAA,GAA2B;AAaxC,IAAI,OAAA,GAAkC,IAAA;AACtC,IAAI,SAAA,GAAY,CAAA;AAKT,SAAS,cAAc,IAAA,EAAwC;AACpE,EAAA,MAAM,QAAQ,EAAE,SAAA;AAChB,EAAA,MAAM,KAAA,GAAyB,EAAE,KAAA,EAAO,IAAA,EAAK;AAC7C,EAAA,OAAA,GAAU,KAAA;AACV,EAAA,OAAO;AAAA,IACL,OAAO,IAAA,EAAsB;AAY3B,MAAA,IAAI,OAAA,KAAY,KAAA,EAAO,KAAA,CAAM,IAAA,GAAO,IAAA;AACpC,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,wBAAA,EAA0B,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,IAAA,EAAM,IAAA,EAAK,EAAG,CAAC,CAAA;AAAA,IACnG;AAAA,GACF;AACF;AAGO,SAAS,mBAAA,GAA8C;AAC5D,EAAA,OAAO,OAAA;AACT;AAKO,SAAS,qBAAqB,KAAA,EAA8B;AACjE,EAAA,IAAI,OAAA,KAAY,OAAO,OAAA,GAAU,IAAA;AACnC","file":"chunk-3L463T5H.js","sourcesContent":["/**\n * PDF Preview staging — the tiny consumer-facing surface of the Preview app.\n *\n * Lives apart from Preview.tsx so importing `setPdfPreview` (from\n * `react-os-shell/apps` or shell internals like PdfActionButton /\n * openPreviewFile) never drags the viewer implementation — and its static\n * pdfjs-dist import — into a host's startup bundle. The Preview window\n * component stays behind its React.lazy dynamic import and drains the stage\n * on mount via the @internal peek/claim helpers below.\n */\n\nexport interface PdfPreviewData {\n /** Object URL or remote URL of the PDF. Blob URLs are revoked when the window unmounts.\n * Leave blank when staging a `converting: true` placeholder; call `handle.update({...})`\n * on the handle returned by `setPdfPreview` once conversion finishes. */\n url?: string;\n /** Display name (and download filename). */\n filename: string;\n /** Renderer to use. Defaults to `'pdf'`. `'dxf'` requires the consumer to\n * have `dxf-viewer` installed (it's an optional peer dep). `'image'`\n * renders an `<img>` for raster screenshots / photos. `'3d'` covers\n * STEP / STL / OBJ / GLTF / 3MF / IGES via the optional\n * `online-3d-viewer` peer dep. */\n kind?: 'pdf' | 'dxf' | 'image' | '3d';\n /** Optional download handler — replaces the built-in \"save URL as filename\" if supplied. */\n onDownload?: () => void;\n /** Optional email handler — only shown when supplied. */\n onEmail?: () => void;\n /** Show a progress placeholder while the consumer fetches/converts the file. */\n converting?: boolean;\n /** Headline shown on the converting placeholder (e.g. \"CONVERTING DWG FILE\"). */\n convertingMessage?: string;\n}\n\n/** Handle returned by `setPdfPreview`. Holds the identity of the staged\n * payload so a later `.update()` only targets the window that picked it up\n * (not every open Preview, which would clobber unrelated windows). */\nexport interface PdfPreviewHandle {\n /** Replace the data shown in the window that consumed this staging. Safe to\n * call before that window exists — an update that lands while the payload\n * is still staged replaces the staged payload, so the window opens on the\n * resolved file instead of the placeholder it was staged with.\n * No-op only once the window that consumed the staging has been closed. */\n update(next: PdfPreviewData): void;\n}\n\n/** @internal Event carrying `.update()` payloads to the claiming window. */\nexport const PDF_PREVIEW_UPDATE_EVENT = 'react-os-shell:pdf-preview-update';\n\n/** @internal Staged payload awaiting the next Preview window mount.\n *\n * `data` is MUTABLE and deliberately so: `update()` rewrites it in place\n * while the stage is still unclaimed. Restaging a fresh object instead would\n * break the identity that `claimPdfPreviewStage` and the claimant's own\n * `consumedRef` are holding. */\nexport interface PendingPdfStage {\n token: number;\n data: PdfPreviewData;\n}\n\nlet pending: PendingPdfStage | null = null;\nlet nextToken = 0;\n\n/** Stage a PDF for the next Preview window mount. The returned handle's\n * `update()` method swaps content in *that* specific window only — use it\n * to replace a `converting: true` placeholder with the resolved file. */\nexport function setPdfPreview(data: PdfPreviewData): PdfPreviewHandle {\n const token = ++nextToken;\n const stage: PendingPdfStage = { token, data };\n pending = stage;\n return {\n update(next: PdfPreviewData) {\n // The window is opened by `openPage('/preview')` and Preview is a lazy\n // chunk, so a consumer that resolves quickly — a cached PDF, a fast\n // endpoint, a second preview in the same session — can call this before\n // any window has mounted to listen. The event is fire-and-forget, so on\n // its own it would be dropped and the window would open on the\n // placeholder and sit there for ever. Rewrite the stage as well while it\n // is still ours: whoever drains it next gets the current payload.\n //\n // `pending === stage` is exactly \"no window has claimed this yet\".\n // Claiming and binding the listener happen in the same commit (see\n // Preview.tsx), so there is no third state where both paths miss.\n if (pending === stage) stage.data = next;\n if (typeof window === 'undefined') return;\n window.dispatchEvent(new CustomEvent(PDF_PREVIEW_UPDATE_EVENT, { detail: { token, data: next } }));\n },\n };\n}\n\n/** @internal Render-phase peek — see Preview.tsx for the drain protocol. */\nexport function peekPdfPreviewStage(): PendingPdfStage | null {\n return pending;\n}\n\n/** @internal Commit-phase claim. The identity check keeps a payload staged\n * *after* the claimant's render-phase peek available for the window it\n * belongs to. */\nexport function claimPdfPreviewStage(stage: PendingPdfStage): void {\n if (pending === stage) pending = null;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/number.ts","../src/shell/strings.tsx"],"names":[],"mappings":"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","file":"chunk-7IN7YZAL.js","sourcesContent":["/**\n * Numbers in the host's locale — or exactly as the kit printed them before it\n * had a locale to print them in.\n *\n * Every helper takes the BCP 47 tag `ShellStringsProvider` was given (read with\n * `useShellLocale`), and every one has two halves. With a tag, `Intl` writes the\n * number the way that locale does: `1.234,5` in German, a narrow space before\n * the percent sign in French. Without one, the helper returns what its call\n * sites used to compute inline — `String(v)`, `v.toFixed(d)`,\n * `v.toLocaleString()` — character for character.\n *\n * The second half is the contract, and the reason the fallbacks are spelled out\n * rather than left to an `Intl` default: `new Intl.NumberFormat()` with no tag\n * is the RUNTIME's locale, and a hard-coded `'en-US'` is somebody else's. An app\n * that never mounts a provider, or mounts one without a locale, must not see a\n * digit move — a table whose totals regrouped themselves on upgrade is a bug\n * report, not a feature.\n *\n * Kit-safe: no React, no DOM.\n */\n\n/** Building an `Intl.NumberFormat` is the expensive part of using one, and a\n * chart formats every tick of every axis on every render. One per locale and\n * option set, for the life of the page. */\nconst formats = new Map<string, Intl.NumberFormat>();\n\nfunction numberFormat(locale: string, options: Intl.NumberFormatOptions): Intl.NumberFormat {\n const key = `${locale}|${JSON.stringify(options)}`;\n let format = formats.get(key);\n if (!format) {\n format = new Intl.NumberFormat(locale, options);\n formats.set(key, format);\n }\n return format;\n}\n\n/**\n * A number as written — `String(v)` without a locale. With one, every digit the\n * value has is kept (up to `Intl`'s ceiling of 20), because the call sites this\n * replaces never rounded: a chart whose caller passed 0.125 printed `0.125`, and\n * `Intl`'s default of three fraction digits would quietly print `0.125` but\n * `0.1235` for 0.12345.\n */\nexport function formatPlain(value: number, locale?: string): string {\n return locale ? numberFormat(locale, { maximumFractionDigits: 20 }).format(value) : String(value);\n}\n\n/** A count with thousands separators — `v.toLocaleString()` without a locale,\n * which is the runtime's own grouping, exactly as before. */\nexport function formatGrouped(value: number, locale?: string): string {\n return locale ? numberFormat(locale, {}).format(value) : value.toLocaleString();\n}\n\n/** Exactly `digits` decimals — `v.toFixed(digits)` without a locale. */\nexport function formatFixed(value: number, digits: number, locale?: string): string {\n return locale\n ? numberFormat(locale, { minimumFractionDigits: digits, maximumFractionDigits: digits }).format(value)\n : value.toFixed(digits);\n}\n\n/**\n * A PERCENTAGE — `37.5`, not the fraction `0.375` — with `digits` decimals:\n * `${p.toFixed(digits)}%` without a locale, the locale's own percent with one\n * (`37,5 %`, `%37,5`).\n *\n * It takes the percentage rather than the fraction because that is what every\n * call site already had in hand: they computed `(share * 100).toFixed(1)`, and\n * passing that same product through keeps the no-locale output identical down to\n * the last floating-point digit.\n */\nexport function formatPercent(percent: number, digits: number, locale?: string): string {\n return locale\n ? numberFormat(locale, {\n style: 'percent', minimumFractionDigits: digits, maximumFractionDigits: digits,\n }).format(percent / 100)\n : `${percent.toFixed(digits)}%`;\n}\n","/**\n * ShellStrings — the shell's user-facing strings, in one typed catalog.\n *\n * Every string here was hardcoded English at its call site, which made the\n * shell untranslatable no matter what the consuming portal did. The catalog\n * is the fix's whole shape: components read strings through `useShellStrings`\n * (which works with NO provider — the English defaults are the context\n * default), and a consumer that wants another language mounts\n * `ShellStringsProvider` once with a partial override. Overrides merge per\n * SECTION, so translating the window controls does not oblige anyone to\n * translate the help viewer.\n *\n * This is deliberately not an i18n library: no message IDs, no interpolation\n * DSL, no plural rules. The shell's strings are labels and short sentences;\n * a typed object keeps them discoverable and lets TypeScript flag a\n * translation that goes stale when a string is added.\n *\n * ── Sentences that carry a value are functions ──\n * \"3 of 40 records\", \"Remove invoice.pdf\", \"Choose a year, currently 2026\".\n * A string with a hole in it would need a template syntax, and a template\n * syntax would need plural rules the moment a count went into the hole —\n * which is the i18n library this file refuses to be. So those entries are\n * plain functions, and the host writes them with whatever it already has:\n * `Intl.PluralRules`, its own message catalog, a ternary.\n *\n * Two rules keep the functions predictable:\n * - A COUNT arrives as a `number`, unformatted, because the words depend on\n * it (\"1 file\", \"2 files\", \"5 файлов\") and a plural rule needs the number.\n * The host formats it; the English defaults do, in the provider's `locale`.\n * - A VALUE the kit already formatted — a date, a caller's `formatValue`\n * output, a file size — arrives as the `string` that would be printed.\n *\n * A few older entries are halves the caller concatenates (`select.remove` +\n * a label, `pageTabs.discardMany` after a count). They stay, so no existing\n * catalog breaks, and each has an optional function beside it that wins when\n * supplied — word order differs between languages, and a concatenation cannot.\n *\n * ── Locale ──\n * `ShellStringsProvider` also takes a `locale` (a BCP 47 tag). It is not a\n * string section, it is how numbers and dates are WRITTEN: month and weekday\n * names in the pickers, `formatDate`, the digits in a list footer or a chart\n * axis. With no locale the kit writes exactly what it always wrote — the same\n * English month names, `toLocaleString()` with no argument, `String(v)` — so\n * mounting the provider for its strings alone changes no number on screen.\n * `useShellLocale` reads it; `src/utils/number.ts` and `calendarNames` in\n * `src/utils/date.ts` are the two halves that honour it.\n *\n * Prop-level text (a `emptyText` prop, a `placeholder`) always wins over the\n * catalog — the catalog replaces hardcoded DEFAULTS, never a caller's words.\n *\n * Kit-safe: no window-manager import, so `react-os-shell/ui` consumers get it\n * too.\n */\nimport { createContext, useContext, useEffect, useMemo, type ReactNode } from 'react';\nimport { formatFixed, formatGrouped, formatPercent, formatPlain } from '../utils/number';\n\nexport interface ShellStrings {\n /** Window chrome: control tooltips and the title bar's accessible name. */\n window: {\n minimize: string;\n /** Bring a hand-minimized window back — the tab's own control. */\n restore: string;\n maximize: string;\n windowed: string;\n pinOnTop: string;\n unpin: string;\n close: string;\n /** Suffix of the title bar's aria-label: `\"{title} — {windowSuffix}\"`. */\n windowSuffix: string;\n prev: string;\n next: string;\n snapLayouts: string;\n snapLeft: string;\n snapRight: string;\n snapTopLeft: string;\n snapTopRight: string;\n snapBottomLeft: string;\n snapBottomRight: string;\n };\n /** Taskbar and exposé. */\n taskbar: {\n closeWindow: string;\n offscreenHint: string;\n offscreenDot: string;\n expose: string;\n addToDesktop: string;\n removeFromDesktop: string;\n /** Group menu — a taskbar tab standing for more than one window. The\n * count is appended by the caller, e.g. \"Close all (3)\". */\n minimizeAllWindows: string;\n restoreAllWindows: string;\n closeAllWindows: string;\n };\n /** The logout cover. */\n logout: {\n goodbye: string;\n seeYou: string;\n };\n /** About + What's New dialogs. */\n about: {\n aboutPrefix: string;\n thisApp: string;\n openSourceLicenses: string;\n whatsNew: string;\n noChangelog: string;\n };\n /** Data-display defaults (DataTable, lists). */\n table: {\n empty: string;\n loading: string;\n selectAll: string;\n selectRow: string;\n };\n /** Picker defaults (SearchableSelect, TagInput). */\n select: {\n none: string;\n noMatches: string;\n allSelected: string;\n clear: string;\n /** aria-label of a TagInput chip's remove button: `\"{remove} {label}\"`. */\n remove: string;\n /** The whole chip label, when the word order is not \"{remove} {label}\".\n * Wins over `remove` when supplied. */\n removeItem?: (label: string) => string;\n };\n /** Notification bell + popup. */\n notifications: {\n title: string;\n markAllRead: string;\n dnd: string;\n dndOn: string;\n caughtUp: string;\n empty: string;\n viewAll: string;\n cardLabel: string;\n dismiss: string;\n };\n /** Form-level messages. */\n form: {\n errorSummaryTitle: string;\n };\n /** HelpCenter chrome. */\n help: {\n title: string;\n searchPlaceholder: string;\n empty: string;\n noResults: string;\n loading: string;\n pickArticle: string;\n noBody: string;\n draft: string;\n newArticle: string;\n edit: string;\n };\n /** The app-update banner (a deploy happened under a long-lived tab). */\n update: {\n available: string;\n refreshNow: string;\n };\n /** The page-tab strip (`react-os-shell/page-tabs`). */\n pageTabs: {\n /** The strip's accessible name. */\n label: string;\n /** A tab's close button, and the menu item: `\"{close} {title}\"` for the button. */\n close: string;\n /** The close button's whole label, when the word order is not\n * \"{close} {title}\". Wins over `close` for the button when supplied. */\n closeTab?: (title: string) => string;\n closeOthers: string;\n closeRight: string;\n closeAll: string;\n /** Marks a tab with unsaved changes (the dot's accessible text). */\n unsaved: string;\n /** Asked before a tab with unsaved changes closes. */\n discardTitle: string;\n discardOne: string;\n /** Several at once — the count is prefixed by the caller: \"3 pages have…\". */\n discardMany: string;\n /** The whole several-at-once sentence, for a language whose noun follows\n * the count's plural form. Wins over `discardMany` when supplied. */\n discardCount?: (count: number) => string;\n discardConfirm: string;\n keepEditing: string;\n };\n /** `Dialog` and `Drawer`'s close control, and the dialogs behind `confirm`,\n * `confirmDestructive` and `prompt` (each option a caller passes wins). */\n dialog: {\n close: string;\n cancel: string;\n ok: string;\n /** `confirm`'s heading when the caller gives no `title`. */\n confirmTitle: string;\n /** `confirmDestructive`'s heading, cancel and confirm defaults. */\n destructiveTitle: string;\n destructiveCancel: string;\n destructiveConfirm: string;\n /** The line over the type-to-confirm box; the word is drawn in a `<kbd>`\n * wherever the sentence puts it. */\n typeToConfirm: (word: string) => string;\n /** `prompt`'s heading when the caller gives no `title`. */\n promptTitle: string;\n };\n /** The month grid (`Calendar`, and the pickers that open it). Month and\n * weekday NAMES are not here — they come from `locale`. */\n calendar: {\n previousMonth: string;\n nextMonth: string;\n previousYear: string;\n nextYear: string;\n previousYears: string;\n nextYears: string;\n /** The month and year panels' accessible names. */\n monthPanel: string;\n yearPanel: string;\n /** The heading's month button. */\n chooseMonth: (month: string) => string;\n /** The heading's year button. */\n chooseYear: (year: number) => string;\n };\n /** `DatePicker`'s trigger and popover. */\n datePicker: {\n placeholder: string;\n /** The popover's accessible name when the field has no `aria-label`. */\n dialog: string;\n clear: string;\n today: string;\n };\n /** `DateRangePicker`. */\n dateRange: {\n placeholder: string;\n /** The trigger's × button. */\n clearRange: string;\n /** The popover's and the grid's accessible name. */\n dialog: string;\n from: string;\n to: string;\n /** The From/To boxes before a day is chosen. */\n start: string;\n end: string;\n /** The trigger with only one end of the range set. */\n fromOnly: (date: string) => string;\n toOnly: (date: string) => string;\n last2Weeks: string;\n lastMonth: string;\n last3Months: string;\n last6Months: string;\n last12Months: string;\n custom: string;\n clear: string;\n cancel: string;\n apply: string;\n };\n /** `Pagination` (and `DataTable`'s pager). */\n pagination: {\n label: string;\n first: string;\n previous: string;\n next: string;\n last: string;\n };\n /** `ListFooter` and `ListLoadError`. `label` is the caller's own noun\n * (\"records\"); the counts are numbers, for the plural. */\n list: {\n /** Before the em dash: \"3 selected — 40 records\". */\n selected: (count: number) => string;\n allLoaded: (total: number, label: string) => string;\n count: (total: number, label: string) => string;\n loadedOf: (loaded: number, total: number, label: string) => string;\n /** After a middle dot: \"40 of 900 records · Loading more...\". */\n loadingMore: string;\n loadError: string;\n loadErrorMessage: string;\n retry: string;\n };\n /** `Kanban`'s defaults (its own props win). */\n kanban: {\n loading: string;\n empty: string;\n dropHere: string;\n addItem: string;\n };\n /** File intake: `FilePicker`, `ComposerAttachments`, and the rejection\n * messages every upload control shares. */\n files: {\n attach: string;\n drop: string;\n remove: (name: string) => string;\n chooseMany: string;\n chooseOne: string;\n /** After the choose link, in the same line. */\n dragMany: string;\n dragOne: string;\n /** `hint` is the caller's `acceptHint` when it is a string, else ''. */\n notAccepted: (name: string, hint: string) => string;\n /** `size` and `limit` arrive written out — \"6.2 MB\". */\n tooLarge: (name: string, size: string, limit: string) => string;\n tooMany: (name: string, max: number) => string;\n bytes: (value: number) => string;\n kilobytes: (value: number) => string;\n megabytes: (value: number) => string;\n };\n /** `MediaUploadField` and `MediaUploadGrid`. */\n media: {\n uploadImage: string;\n uploadVideo: string;\n uploadFile: string;\n /** The drop zone's accessible name when its prompt is not a string. */\n upload: string;\n cta: string;\n replace: string;\n remove: string;\n uploading: string;\n cover: string;\n add: string;\n addMedia: string;\n empty: string;\n removeItem: (name: string) => string;\n /** A reorderable thumbnail's accessible name. */\n reorder: (name: string, position: number, total: number) => string;\n };\n /** `BrandAssetEditor`. `noun` is the last word of `assetName`, lower-cased\n * (\"Portal logo\" → \"logo\"); a translation that cannot use it has\n * `assetName` itself. */\n brandAsset: {\n save: (noun: string, assetName: string) => string;\n remove: (noun: string, assetName: string) => string;\n discard: string;\n saveFailed: (noun: string, assetName: string) => string;\n removeFailed: (noun: string, assetName: string) => string;\n region: (assetName: string, subjectName: string) => string;\n usedFor: (subjectName: string) => string;\n previews: (assetName: string) => string;\n preview: string;\n alt: (subjectName: string, assetName: string) => string;\n };\n /** `Snippet`'s copy button, and the clipboard's toasts. */\n copy: {\n copy: string;\n copyLabel: (label: string) => string;\n /** Snippet's spoken confirmation. */\n copied: string;\n /** `copyToClipboard`'s success toast; `label` names what was copied. */\n copiedLabel: (label: string) => string;\n failed: string;\n };\n /** `NumericKeypad`. */\n keypad: {\n backspace: string;\n enter: string;\n };\n /** `Banner`. */\n banner: {\n dismiss: string;\n };\n /** A closable `ColoredBadge`'s × (its `closeLabel` wins). */\n badge: {\n /** When the badge's content is not plain text. */\n remove: string;\n removeItem: (label: string) => string;\n };\n /** `Breadcrumbs`. */\n breadcrumbs: {\n label: string;\n /** The ellipsis standing for the crumbs `maxItems` folded away. */\n hidden: string;\n };\n /** `EmptyState`'s line when the caller gives neither a title nor a message. */\n emptyState: {\n message: string;\n };\n /** `ErrorPage`, `ErrorBoundary` and `Result`'s status defaults. */\n errors: {\n notFound: string;\n notFoundBody: string;\n forbidden: string;\n forbiddenBody: string;\n /** `Result status=\"403\"`'s title — gentler than `ErrorPage`'s. */\n noAccess: string;\n serverError: string;\n serverErrorBody: string;\n retry: string;\n details: string;\n };\n /** `GlobalSearch`. */\n search: {\n placeholder: string;\n /** The key cap beside the input. */\n escBadge: string;\n searching: string;\n noResults: string;\n minChars: (min: number) => string;\n navigate: string;\n open: string;\n close: string;\n enterKey: string;\n escKey: string;\n };\n /** `EditableGrid`. */\n grid: {\n selectAll: string;\n insertRowAbove: string;\n insertRowBelow: string;\n deleteRow: (row: number) => string;\n insertColumnLeft: string;\n insertColumnRight: string;\n deleteColumn: (column: string) => string;\n resize: string;\n fill: string;\n };\n /** `SidebarLayout`'s resize handle. */\n sidebar: {\n resize: string;\n };\n /** `MarkdownLite`. */\n markdown: {\n /** Before an image placeholder's caption, with an em dash between. */\n screenshot: string;\n };\n /** The word a severity marker is spoken and tooltipped with. */\n severity: {\n success: string;\n warning: string;\n danger: string;\n /** A token that is not one of the three, as received. */\n unrecognised: (token: string) => string;\n };\n /** `MetricBar` and `BudgetBar`. */\n meter: {\n noData: string;\n warningAt: (bound: number) => string;\n criticalAt: (bound: number) => string;\n noReading: string;\n noBudget: string;\n /** The meter's spoken value: \"84% of budget\". */\n ofBudget: (value: string) => string;\n /** The deadline marker's tooltip. */\n budget: string;\n hoursMinutes: (hours: number, minutes: number) => string;\n minutesSeconds: (minutes: number, seconds: number) => string;\n seconds: (seconds: number) => string;\n };\n /** The chart family. Series, axis and category names are the caller's. */\n charts: {\n showTable: string;\n loading: string;\n noData: string;\n windowStart: string;\n windowEnd: string;\n window: (from: string, to: string, count: number) => string;\n overIntervals: (series: string[], count: number) => string;\n acrossCategories: (series: string[], count: number) => string;\n acrossMeasures: (series: string[], count: number) => string;\n /** The pie's accessible name; `total` is written by the caller's `formatValue`. */\n breakdown: (total: string, segments: number) => string;\n funnel: (stages: number, first: string, last: string) => string;\n radialTrack: (count: number) => string;\n radialCycle: (count: number) => string;\n /** Column heads of the screen-reader tables some charts carry. */\n tableFrom: string;\n tableTo: string;\n tableItem: string;\n tableLevel: string;\n tableSeries: string;\n inBucket: (total: string) => string;\n inCategory: (total: string) => string;\n value: string;\n share: string;\n count: string;\n flow: string;\n totalFlow: string;\n throughput: string;\n open: string;\n high: string;\n low: string;\n close: string;\n maximum: string;\n q3: string;\n median: string;\n q1: string;\n minimum: string;\n distribution: string;\n fiveNumber: (label: string, count: number) => string;\n outliers: (count: number) => string;\n price: string;\n ohlc: (label: string, count: number) => string;\n closedAbove: string;\n closedBelow: string;\n noFlows: string;\n chord: (count: number) => string;\n noStages: string;\n ofFirstStage: string;\n droppedHere: string;\n intensity: string;\n noActivity: string;\n heatmap: (label: string, rows: number, columns: number) => string;\n /** A histogram's y-axis title. */\n countAxis: string;\n histogram: (label: string, bins: number, observations: number) => string;\n observations: string;\n /** `Meter` with no value to judge. */\n notEnough: string;\n objectiveMet: (objective: string) => string;\n objectiveMissed: (objective: string) => string;\n nothingToPlot: string;\n nothingToCompare: string;\n /** The pie slice the small segments are folded into. */\n other: string;\n nothingToBreakDown: string;\n range: string;\n rangeLabel: (label: string, count: number) => string;\n nothingToRank: string;\n /** Spoken after the emphasised row of `RankedBars`. */\n emphasised: string;\n sankey: (nodes: number, links: number) => string;\n noObservations: string;\n xAxis: string;\n yAxis: string;\n size: string;\n scatter: (series: string[], yLabel: string, xLabel: string) => string;\n outsideRange: (count: number) => string;\n waterfall: (steps: number, from: string, to: string) => string;\n balance: string;\n increase: string;\n decrease: string;\n runningTotal: string;\n sunburst: (total: string, depth: number) => string;\n treemap: (count: number) => string;\n /** `StatTile`'s delta direction, spoken after the arrow glyph. */\n trendUp: string;\n trendDown: string;\n trendFlat: string;\n };\n /** `TimelineTrack` and `MilestoneTimeline`. */\n timeline: {\n /** A cut in the axis: \"412 days\". */\n days: (count: number) => string;\n daysToToday: (count: number) => string;\n notReached: string;\n /** Before the first pending entry, with a middle dot after it. */\n next: string;\n more: (count: number) => string;\n today: string;\n todayTitle: (date: string) => string;\n open: (name: string) => string;\n openButton: string;\n scrub: string;\n alsoToCome: (names: string[]) => string;\n start: (date: string) => string;\n /** A folded run of marks: its count, then each member's own name. */\n events: (count: number, names: string[]) => string;\n started: (date: string) => string;\n duration: (days: number) => string;\n reached: (dated: number, total: number) => string;\n milestones: (title: string) => string;\n };\n /** `ProductionTimeline`. */\n production: {\n heading: string;\n /** The synthetic report standing for the production start. */\n start: string;\n /** The synthetic report between two real ones. */\n estimated: string;\n estimatedCompletion: string;\n estDone: string;\n play: string;\n pause: string;\n playTitle: string;\n backTo: (report: string) => string;\n /** The report is drawn bold wherever the sentence puts it. */\n showing: (report: string) => string;\n overall: (percent: number) => string;\n inStock: (pieces: number) => string;\n noReport: string;\n leadTime: (days: number) => string;\n report: string;\n shipment: string;\n inspection: string;\n invoice: string;\n scrub: string;\n label: (from: string, to: string) => string;\n };\n /** `ContainerFillChart`. Volumes are cubic metres. */\n containers: {\n items: (count: number) => string;\n pieces: (count: number) => string;\n split: (instructed: number, loaded: number) => string;\n added: (count: number, pieces: number) => string;\n fill: (volume: number, capacity: number) => string;\n total: string;\n instructed: (volume: number) => string;\n loaded: (volume: number) => string;\n volume: (volume: number) => string;\n noVolume: string;\n };\n /** `toast.notify`'s card. */\n toast: {\n notification: string;\n };\n}\n\n/**\n * The English catalog, with its numbers written for `locale`.\n *\n * A function, not a literal, because the defaults that carry a count have to\n * write it the way the provider's locale does — `1.234 records` is still the\n * English default, in a German-formatted app — and the locale is not known\n * until a provider says so. With no locale every number is written exactly as\n * the component wrote it inline before (`toLocaleString()` where it grouped,\n * a bare interpolation where it did not), which is what makes\n * `DEFAULT_SHELL_STRINGS` byte-identical to the strings it replaced.\n */\nfunction englishStrings(locale?: string): ShellStrings {\n const plain = (v: number) => formatPlain(v, locale);\n const grouped = (v: number) => formatGrouped(v, locale);\n const fixed = (v: number, digits: number) => formatFixed(v, digits, locale);\n const percent = (p: number, digits: number) => formatPercent(p, digits, locale);\n return {\n window: {\n minimize: 'Minimize',\n restore: 'Restore',\n maximize: 'Maximize',\n windowed: 'Windowed',\n pinOnTop: 'Pin on top',\n unpin: 'Unpin from top',\n close: 'Close',\n windowSuffix: 'window',\n prev: 'Prev',\n next: 'Next',\n snapLayouts: 'Snap layouts',\n snapLeft: 'Snap left half',\n snapRight: 'Snap right half',\n snapTopLeft: 'Snap top-left quarter',\n snapTopRight: 'Snap top-right quarter',\n snapBottomLeft: 'Snap bottom-left quarter',\n snapBottomRight: 'Snap bottom-right quarter',\n },\n taskbar: {\n closeWindow: 'Close window',\n offscreenHint: 'This window is off screen — click to bring it back',\n offscreenDot: 'Off screen — click to bring this window back',\n expose: 'Exposé — show all open windows as thumbnails',\n addToDesktop: 'Add to desktop',\n removeFromDesktop: 'Remove from desktop',\n minimizeAllWindows: 'Minimize all',\n restoreAllWindows: 'Restore all',\n closeAllWindows: 'Close all',\n },\n logout: {\n goodbye: 'Goodbye',\n seeYou: 'See you next time',\n },\n about: {\n aboutPrefix: 'About',\n thisApp: 'this app',\n openSourceLicenses: 'Open Source Licenses',\n whatsNew: \"What's New\",\n noChangelog: 'No changelog available.',\n },\n table: {\n empty: 'Nothing to show',\n loading: 'Loading',\n selectAll: 'Select all rows',\n selectRow: 'Select row',\n },\n select: {\n none: '— None —',\n noMatches: 'No matches',\n allSelected: 'All options selected',\n clear: 'Clear selection',\n remove: 'Remove',\n },\n notifications: {\n title: 'Notifications',\n markAllRead: 'Mark all read',\n dnd: 'Do not disturb',\n dndOn: 'Do not disturb is on',\n caughtUp: 'All caught up',\n empty: 'No notifications yet',\n viewAll: 'View all notifications',\n cardLabel: 'Notification',\n dismiss: 'Dismiss notification',\n },\n form: {\n errorSummaryTitle: 'There is a problem',\n },\n help: {\n title: 'Help',\n searchPlaceholder: 'Search help…',\n empty: 'No help articles yet.',\n noResults: 'No articles match your search.',\n loading: 'Loading…',\n pickArticle: 'Pick a help article from the left.',\n noBody: 'This article has no body yet.',\n draft: 'Draft',\n newArticle: '+ New',\n edit: 'Edit',\n },\n update: {\n available: 'A new version is available.',\n refreshNow: 'Refresh now',\n },\n pageTabs: {\n label: 'Open pages',\n close: 'Close',\n closeOthers: 'Close other tabs',\n closeRight: 'Close tabs to the right',\n closeAll: 'Close all tabs',\n unsaved: 'Unsaved changes',\n discardTitle: 'Discard unsaved changes?',\n discardOne: 'This page has changes that have not been saved. Close it anyway?',\n discardMany: 'pages have changes that have not been saved. Close them anyway?',\n discardConfirm: 'Discard and close',\n keepEditing: 'Keep editing',\n },\n dialog: {\n close: 'Close',\n cancel: 'Cancel',\n ok: 'OK',\n confirmTitle: 'Confirm',\n destructiveTitle: 'Confirm Action',\n destructiveCancel: 'Dismiss',\n destructiveConfirm: 'Delete',\n typeToConfirm: word => `Type ${word} to confirm:`,\n promptTitle: 'Enter a value',\n },\n calendar: {\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n previousYear: 'Previous year',\n nextYear: 'Next year',\n previousYears: 'Previous years',\n nextYears: 'Next years',\n monthPanel: 'Choose a month',\n yearPanel: 'Choose a year',\n chooseMonth: month => `Choose a month, currently ${month}`,\n // A year is never grouped: \"2,026\" is a quantity, not a year.\n chooseYear: year => `Choose a year, currently ${year}`,\n },\n datePicker: {\n placeholder: 'Select a date',\n dialog: 'Choose a date',\n clear: 'Clear',\n today: 'Today',\n },\n dateRange: {\n placeholder: 'Date Range',\n clearRange: 'Clear date range',\n dialog: 'Date range',\n from: 'From',\n to: 'To',\n start: 'Start',\n end: 'End',\n fromOnly: date => `From ${date}`,\n toOnly: date => `To ${date}`,\n last2Weeks: 'Last 2 Weeks',\n lastMonth: 'Last Month',\n last3Months: 'Last 3 Months',\n last6Months: 'Last 6 Months',\n last12Months: 'Last 12 Months',\n custom: 'Custom',\n clear: 'Clear',\n cancel: 'Cancel',\n apply: 'Apply',\n },\n pagination: {\n label: 'Pagination',\n first: 'First page',\n previous: 'Previous page',\n next: 'Next page',\n last: 'Last page',\n },\n list: {\n selected: count => `${plain(count)} selected`,\n allLoaded: (total, label) => `All ${grouped(total)} ${label} loaded`,\n count: (total, label) => `${grouped(total)} ${label}`,\n loadedOf: (loaded, total, label) => `${grouped(loaded)} of ${grouped(total)} ${label}`,\n loadingMore: 'Loading more...',\n loadError: \"Couldn't load this list\",\n loadErrorMessage: 'Something went wrong fetching these records. Check your connection and try again.',\n retry: 'Try again',\n },\n kanban: {\n loading: 'Loading…',\n empty: 'No items.',\n dropHere: 'Drop here',\n addItem: 'Add item',\n },\n files: {\n attach: 'Attach files',\n drop: 'Drop files to attach',\n remove: name => `Remove ${name}`,\n chooseMany: 'Choose files',\n chooseOne: 'Choose a file',\n dragMany: 'or drag them here',\n dragOne: 'or drag it here',\n notAccepted: (name, hint) => `${name} is not an accepted file type${hint ? ` (${hint})` : ''}`,\n tooLarge: (name, size, limit) => `${name} is ${size} — the limit is ${limit}`,\n tooMany: (name, max) => `${name} was not added — ${plain(max)} ${max === 1 ? 'file' : 'files'} is the limit`,\n bytes: value => `${plain(value)} B`,\n kilobytes: value => `${plain(value)} KB`,\n megabytes: value => `${fixed(value, 1)} MB`,\n },\n media: {\n uploadImage: 'Upload an image',\n uploadVideo: 'Upload a video',\n uploadFile: 'Upload a file',\n upload: 'Upload media',\n cta: 'Choose from library or upload',\n replace: 'Replace',\n remove: 'Remove',\n uploading: 'Uploading…',\n cover: 'Cover',\n add: 'Add',\n addMedia: 'Add media',\n empty: 'No media.',\n removeItem: name => `Remove ${name}`,\n reorder: (name, position, total) =>\n `${name}, item ${plain(position)} of ${plain(total)}. Use arrow keys to reorder.`,\n },\n brandAsset: {\n save: noun => `Save ${noun}`,\n remove: noun => `Remove ${noun}`,\n discard: 'Discard change',\n saveFailed: noun => `Could not save ${noun}.`,\n removeFailed: noun => `Could not remove ${noun}.`,\n region: (assetName, subjectName) => `${assetName} for ${subjectName}`,\n usedFor: subjectName => `Used for ${subjectName}.`,\n previews: assetName => `${assetName} previews`,\n preview: 'Preview',\n alt: (subjectName, assetName) => `${subjectName} ${assetName}`,\n },\n copy: {\n copy: 'Copy',\n copyLabel: label => `Copy ${label}`,\n copied: 'Copied',\n copiedLabel: label => `${label} copied`,\n failed: 'Could not copy to the clipboard',\n },\n keypad: {\n backspace: 'Backspace',\n enter: 'Enter',\n },\n banner: {\n dismiss: 'Dismiss',\n },\n badge: {\n remove: 'Remove',\n removeItem: label => `Remove ${label}`,\n },\n breadcrumbs: {\n label: 'Breadcrumb',\n hidden: 'Hidden crumbs',\n },\n emptyState: {\n message: 'Nothing here yet.',\n },\n errors: {\n notFound: 'Page not found',\n notFoundBody: \"The page you're looking for doesn't exist or was moved.\",\n forbidden: 'Access denied',\n forbiddenBody: \"You don't have permission to view this page.\",\n noAccess: \"You don't have access to this\",\n serverError: 'Something went wrong',\n serverErrorBody: 'An unexpected error occurred. Please try again.',\n retry: 'Try again',\n details: 'Error details',\n },\n search: {\n placeholder: 'Search...',\n escBadge: 'ESC',\n searching: 'Searching...',\n noResults: 'No results found.',\n minChars: min => `Type at least ${plain(min)} characters to search...`,\n navigate: 'navigate',\n open: 'open',\n close: 'close',\n enterKey: 'Enter',\n escKey: 'Esc',\n },\n grid: {\n selectAll: 'Select all',\n insertRowAbove: 'Insert row above',\n insertRowBelow: 'Insert row below',\n // A row NUMBER, as the grid's own row header prints it — never grouped.\n deleteRow: row => `Delete row ${row}`,\n insertColumnLeft: 'Insert column left',\n insertColumnRight: 'Insert column right',\n deleteColumn: column => `Delete column ${column}`,\n resize: 'Drag to resize · double-click to auto-fit',\n fill: 'Drag to fill',\n },\n sidebar: {\n resize: 'Drag to resize · double-click to reset',\n },\n markdown: {\n screenshot: 'Screenshot',\n },\n severity: {\n success: 'ok',\n warning: 'warning',\n danger: 'critical',\n unrecognised: token => `unrecognised severity ${token}`,\n },\n meter: {\n noData: 'no data',\n warningAt: bound => `warning ≥ ${plain(bound)}`,\n criticalAt: bound => `critical ≥ ${plain(bound)}`,\n noReading: 'no reading',\n noBudget: 'no budget',\n ofBudget: value => `${value} of budget`,\n budget: 'budget',\n hoursMinutes: (hours, minutes) => `${plain(hours)}h ${plain(minutes)}m`,\n minutesSeconds: (minutes, seconds) => `${plain(minutes)}m ${plain(seconds)}s`,\n seconds: seconds => `${plain(seconds)}s`,\n },\n charts: {\n showTable: 'Show the data as a table',\n loading: 'Loading chart data',\n noData: 'No data in this window.',\n windowStart: 'Window start',\n windowEnd: 'Window end',\n window: (from, to, count) => `Time window — showing ${from} to ${to} of ${plain(count)} intervals`,\n overIntervals: (series, count) => `${series.join(', ')} over ${plain(count)} intervals`,\n acrossCategories: (series, count) => `${series.join(', ')} across ${plain(count)} categories`,\n acrossMeasures: (series, count) => `${series.join(', ')} across ${plain(count)} measures`,\n breakdown: (total, segments) => `Breakdown of ${total} across ${plain(segments)} segments`,\n funnel: (stages, first, last) => `Funnel of ${plain(stages)} stages, ${first} down to ${last}`,\n radialTrack: count => `${plain(count)} categories, as concentric proportions`,\n radialCycle: count => `${plain(count)} categories, around a cycle`,\n tableFrom: 'From',\n tableTo: 'To',\n tableItem: 'Item',\n tableLevel: 'Level',\n tableSeries: 'Series',\n inBucket: total => `${total} in this bucket`,\n inCategory: total => `${total} in this category`,\n value: 'Value',\n share: 'Share',\n count: 'Count',\n flow: 'Flow',\n totalFlow: 'Total flow',\n throughput: 'Throughput',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n maximum: 'Maximum',\n q3: 'Q3',\n median: 'Median',\n q1: 'Q1',\n minimum: 'Minimum',\n distribution: 'Distribution',\n fiveNumber: (label, count) => `${label}: five-number summary for ${plain(count)} categories`,\n outliers: count => `${plain(count)} outlier${count > 1 ? 's' : ''} beyond the whiskers`,\n price: 'Price',\n ohlc: (label, count) => `${label}: open, high, low and close across ${plain(count)} periods`,\n closedAbove: 'Closed above its open',\n closedBelow: 'Closed below its open',\n noFlows: 'No flows to chart.',\n chord: count => `Flows between ${plain(count)} participants`,\n noStages: 'No stages to chart.',\n ofFirstStage: 'Of first stage',\n droppedHere: 'Dropped here',\n intensity: 'Intensity',\n noActivity: 'No activity in this window.',\n heatmap: (label, rows, columns) => `${label} across ${plain(rows)} rows and ${plain(columns)} columns`,\n countAxis: 'count',\n histogram: (label, bins, observations) =>\n `${label}: ${plain(bins)} bins over ${plain(observations)} observations`,\n observations: 'Observations',\n notEnough: 'Not enough eligible requests to judge.',\n objectiveMet: objective => `objective ${objective} met`,\n objectiveMissed: objective => `objective ${objective} missed`,\n nothingToPlot: 'Nothing to plot.',\n nothingToCompare: 'Nothing to compare.',\n other: 'Other',\n nothingToBreakDown: 'Nothing to break down.',\n range: 'Range',\n rangeLabel: (label, count) => `${label}: low and high across ${plain(count)} categories`,\n nothingToRank: 'Nothing to rank in this window.',\n emphasised: '(emphasised)',\n sankey: (nodes, links) => `Flow between ${plain(nodes)} nodes over ${plain(links)} links`,\n noObservations: 'No observations in this window.',\n xAxis: 'x',\n yAxis: 'y',\n size: 'Size',\n scatter: (series, yLabel, xLabel) => `${series.join(', ')}: ${yLabel} against ${xLabel}`,\n outsideRange: count => `${plain(count)} ${count === 1 ? 'point' : 'points'} outside the shown range`,\n waterfall: (steps, from, to) => `Waterfall of ${plain(steps)} steps from ${from} to ${to}`,\n balance: 'Balance',\n increase: 'Increase',\n decrease: 'Decrease',\n runningTotal: 'Running total',\n sunburst: (total, depth) => `Hierarchy of ${total} across ${plain(depth)} levels`,\n treemap: count => `Treemap of ${plain(count)} items`,\n trendUp: 'up',\n trendDown: 'down',\n trendFlat: 'flat',\n },\n timeline: {\n days: count => `${grouped(count)} days`,\n daysToToday: count => `${grouped(count)} days to today`,\n notReached: 'Not yet reached',\n next: 'Next',\n more: count => `+${plain(count)} more`,\n today: 'Today',\n todayTitle: date => `Today — ${date}`,\n open: name => `Open ${name}`,\n openButton: 'Open',\n scrub: 'Scrub the timeline',\n alsoToCome: names => `Also to come: ${names.join(', ')}`,\n start: date => `Start · ${date}`,\n events: (count, names) => `${plain(count)} events · ${names.join(', ')}`,\n started: date => `started ${date}`,\n duration: days => `${grouped(days)} day${days === 1 ? '' : 's'}`,\n reached: (dated, total) => `${plain(dated)} of ${plain(total)} milestones`,\n milestones: title => `${title} milestones`,\n },\n production: {\n heading: 'Production progress',\n start: 'Start',\n estimated: 'Estimated',\n estimatedCompletion: 'Estimated completion',\n estDone: 'Est. done',\n play: 'Play',\n pause: 'Pause',\n playTitle: 'Play the timeline, report by report',\n backTo: report => `Back to ${report}`,\n showing: report => `Showing ${report}`,\n overall: p => `${percent(p, 0)} overall`,\n inStock: pieces => `${grouped(pieces)} pc in stock`,\n noReport: 'No production report filed yet',\n leadTime: days => `${grouped(days)} day${days === 1 ? '' : 's'} lead time`,\n report: 'Production report',\n shipment: 'Shipment',\n inspection: 'Inspection',\n invoice: 'Invoice',\n scrub: 'Scrub the production timeline',\n label: (from, to) => `Production reports and events, ${from} to ${to}`,\n },\n containers: {\n items: count => `${plain(count)} items`,\n pieces: count => `${plain(count)} pcs`,\n split: (instructed, loaded) => `(${plain(instructed)} instr / ${plain(loaded)} loaded)`,\n added: (count, pieces) => `${plain(count)} new (${plain(pieces)} pcs)`,\n fill: (volume, capacity) => `${fixed(volume, 1)} / ${plain(capacity)} m³`,\n total: 'Total:',\n instructed: volume => `${fixed(volume, 2)} m³ instruction`,\n loaded: volume => `${fixed(volume, 2)} m³ loaded`,\n volume: volume => `${fixed(volume, 2)} m³`,\n noVolume: 'Volume: N/A (no volume data for these part numbers)',\n },\n toast: {\n notification: 'Notification',\n },\n };\n}\n\nexport const DEFAULT_SHELL_STRINGS: ShellStrings = englishStrings();\n\n/** The English defaults per locale — a provider re-rendering with the same\n * locale gets the same object, so its merge memo holds. */\nconst localisedDefaults = new Map<string, ShellStrings>();\n\nfunction defaultsFor(locale: string | undefined): ShellStrings {\n if (!locale) return DEFAULT_SHELL_STRINGS;\n let defaults = localisedDefaults.get(locale);\n if (!defaults) {\n defaults = englishStrings(locale);\n localisedDefaults.set(locale, defaults);\n }\n return defaults;\n}\n\n/** A per-section partial: override any subset of a section's strings. */\nexport type ShellStringsOverride = {\n [S in keyof ShellStrings]?: Partial<ShellStrings[S]>;\n};\n\nconst ShellStringsContext = createContext<ShellStrings>(DEFAULT_SHELL_STRINGS);\n\n/** `null` outside any provider — which is how a provider tells it is nested. */\nconst ShellLocaleContext = createContext<{ locale: string | undefined } | null>(null);\n\nconst reportedLocales = new Set<string>();\n\n/**\n * The tag in canonical form, or `undefined` for one `Intl` refuses.\n *\n * Refused here, once, rather than at every formatter: `new Intl.DateTimeFormat\n * ('en_US')` throws, and a malformed tag would otherwise take down whichever\n * component formatted a number first — in render, where the error boundary is\n * the only thing left to catch it. A tag that is well formed but names nothing\n * the runtime has (`xx-YY`) is not an error: `Intl` falls back on its own.\n */\nfunction canonicalLocale(tag: string | undefined): string | undefined {\n if (!tag) return undefined;\n try {\n return Intl.getCanonicalLocales(tag)[0];\n } catch {\n if (!reportedLocales.has(tag)) {\n reportedLocales.add(tag);\n console.error(\n `[react-os-shell] ShellStringsProvider: locale=\"${tag}\" is not a BCP 47 language tag, so it is ` +\n 'ignored and numbers and dates keep their default formatting. Pass a tag such as \"de-DE\" or \"ja\".',\n );\n }\n return undefined;\n }\n}\n\n/**\n * The catalog for code that runs outside React — `toast` builds its DOM by\n * hand, long after any render. It follows the OUTERMOST mounted provider (the\n * app's own, not a subtree's), and is the English defaults when none is\n * mounted. Not part of the public surface: components read `useShellStrings`.\n */\nlet outermost: ShellStrings = DEFAULT_SHELL_STRINGS;\n\n/** One empty override for every provider given none — a fresh `{}` per render\n * would re-merge, and re-render every reader, each time the provider did. */\nconst NO_OVERRIDE: ShellStringsOverride = {};\n\nexport function currentShellStrings(): ShellStrings {\n return outermost;\n}\n\n/**\n * Mount once, near the top of the app. `value` is a partial — sections and\n * keys you do not translate keep their English defaults, so a catalog never\n * breaks by falling behind a release.\n *\n * `locale` is a BCP 47 tag (`'de-DE'`, `'ja'`, `'zh-Hant'`) for how numbers and\n * dates are written; omit it and they are written exactly as without a\n * provider. A nested provider without a `locale` keeps its parent's — a subtree\n * that overrides one string should not lose the app's number format. Strings\n * do not cascade that way: a nested provider's `value` merges onto the English\n * defaults, as it always has.\n */\nexport function ShellStringsProvider({ value = NO_OVERRIDE, locale, children }: {\n value?: ShellStringsOverride;\n locale?: string;\n children: ReactNode;\n}) {\n const parent = useContext(ShellLocaleContext);\n const own = useMemo(() => canonicalLocale(locale), [locale]);\n const active = locale === undefined ? parent?.locale : own;\n const merged = useMemo<ShellStrings>(() => {\n const base = defaultsFor(active);\n const out = {} as ShellStrings;\n for (const key of Object.keys(base) as (keyof ShellStrings)[]) {\n out[key] = { ...base[key], ...(value[key] ?? {}) } as never;\n }\n return out;\n }, [value, active]);\n const localeValue = useMemo(() => ({ locale: active }), [active]);\n\n const nested = parent !== null;\n useEffect(() => {\n if (nested) return;\n outermost = merged;\n return () => {\n if (outermost === merged) outermost = DEFAULT_SHELL_STRINGS;\n };\n }, [merged, nested]);\n\n return (\n <ShellLocaleContext.Provider value={localeValue}>\n <ShellStringsContext.Provider value={merged}>{children}</ShellStringsContext.Provider>\n </ShellLocaleContext.Provider>\n );\n}\n\n/** The active catalog — English defaults when no provider is mounted. */\nexport function useShellStrings(): ShellStrings {\n return useContext(ShellStringsContext);\n}\n\n/**\n * The provider's `locale`, canonicalised — `undefined` when there is no\n * provider or it was given none. Hand it to `formatDate(value, { locale })`,\n * `fmtSliderDate(ms, locale)`, or `Intl` directly, so a host's own cells write\n * numbers and dates the way the kit's do.\n */\nexport function useShellLocale(): string | undefined {\n return useContext(ShellLocaleContext)?.locale;\n}\n\n/**\n * The text either side of the value in a catalog sentence, for the few\n * sentences that wrap their value in markup of its own — \"Type <kbd>DELETE</kbd>\n * to confirm:\", \"Showing <b>PR-7</b>\".\n *\n * The entry stays a plain `(word) => string`, so a translator writes a sentence\n * and puts the word wherever their language does; the kit calls it with a\n * marker no sentence contains and splits there. A sentence that leaves the word\n * out entirely comes back whole, as the text before it.\n */\nexport function splitAround(sentence: (slot: string) => string): [string, string] {\n const MARK = '\\u0000';\n const [before = '', ...after] = sentence(MARK).split(MARK);\n return [before, after.join('')];\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/_browserStage.ts"],"names":[],"mappings":";AAeA,IAAI,eAAA,GAA0C,IAAA;AAC9C,IAAI,cAAA,GAAiB,CAAA;AAKd,SAAS,mBAAmB,GAAA,EAAmB;AACpD,EAAA,eAAA,GAAkB,EAAE,KAAA,EAAO,EAAE,cAAA,EAAgB,GAAA,EAAI;AACnD;AAGO,SAAS,mBAAA,GAA8C;AAC5D,EAAA,OAAO,eAAA;AACT;AAKO,SAAS,qBAAqB,KAAA,EAA8B;AACjE,EAAA,IAAI,eAAA,KAAoB,OAAO,eAAA,GAAkB,IAAA;AACnD","file":"chunk-BFBWLCO6.js","sourcesContent":["/**\n * Browser start-URL staging — the tiny consumer-facing surface of the Browser\n * app. Lives apart from Browser.tsx so importing `setBrowserStartUrl` (from\n * `react-os-shell/apps`) never drags the Browser implementation into a host's\n * startup bundle. The Browser window component stays behind its React.lazy\n * dynamic import and drains the stage on mount via the @internal peek/claim\n * helpers below.\n */\n\n/** @internal Staged URL awaiting the next Browser window mount. */\nexport interface PendingStartUrl {\n token: number;\n url: string;\n}\n\nlet pendingStartUrl: PendingStartUrl | null = null;\nlet nextStartToken = 0;\n\n/** Stage a URL for the next Browser window mount — pair with\n * `openPage('/browser')`. Used by \"open this link in the Browser\" flows\n * (e.g. links inside an email body). */\nexport function setBrowserStartUrl(url: string): void {\n pendingStartUrl = { token: ++nextStartToken, url };\n}\n\n/** @internal Render-phase peek — see Browser.tsx for the drain protocol. */\nexport function peekBrowserStartUrl(): PendingStartUrl | null {\n return pendingStartUrl;\n}\n\n/** @internal Commit-phase claim. The identity check keeps a URL staged\n * *after* the claimant's render-phase peek available for the window it\n * belongs to. */\nexport function claimBrowserStartUrl(stage: PendingStartUrl): void {\n if (pendingStartUrl === stage) pendingStartUrl = null;\n}\n"]}
|