@domicile-desktop/component-library 0.0.0-alpha-3ee3ca09c591 → 0.0.0-alpha-14e607160f4e

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/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "dependencies": {
3
3
  "@base-ui/react": "^1.8.0",
4
4
  "@cprussin/option-result": "^2.0.1",
5
- "@domicile-desktop/sdk": "0.0.0-alpha-3ee3ca09c591",
6
- "@domicile-desktop/system-apps": "0.0.0-alpha-3ee3ca09c591",
5
+ "@domicile-desktop/sdk": "0.0.0-alpha-14e607160f4e",
6
+ "@domicile-desktop/system-apps": "0.0.0-alpha-14e607160f4e",
7
7
  "@pandacss/dev": "^1.12.1",
8
8
  "@phosphor-icons/react": "^2.1.10"
9
9
  },
@@ -89,6 +89,7 @@
89
89
  "files": [
90
90
  "src/**",
91
91
  "styled-system/**",
92
+ "!styled-system/styles.css",
92
93
  "!src/**/*.test.ts",
93
94
  "!src/**/*.test.tsx",
94
95
  "!src/**/*.stories.tsx",
@@ -111,12 +112,12 @@
111
112
  },
112
113
  "scripts": {
113
114
  "build:storybook": "storybook build",
114
- "prepare": "panda codegen --silent",
115
+ "prepare": "panda codegen --silent && panda cssgen --silent",
115
116
  "start:dev": "storybook dev -p 4000",
116
117
  "start:prod": "http-server storybook-static -p 4000",
117
118
  "test:types": "tsc --noEmit",
118
119
  "test:unit": "bun test"
119
120
  },
120
121
  "type": "module",
121
- "version": "0.0.0-alpha-3ee3ca09c591"
122
+ "version": "0.0.0-alpha-14e607160f4e"
122
123
  }
@@ -9,12 +9,10 @@ import {
9
9
  } from "@domicile-desktop/sdk/portal";
10
10
  import { useState } from "react";
11
11
  import { css } from "../../styled-system/css";
12
- import { focusOnAttach } from "../_control/focusOnAttach";
13
- import { FilePicker } from "../FilePicker/FilePicker";
14
12
  import { ChooserMode } from "../FilePicker/file-request";
15
13
  import type { Folders } from "../FilePicker/folders";
16
- import { useScreenRegion } from "../Screen/DisplayProvider";
17
14
  import { Select } from "../Select/Select";
15
+ import { ModalFilePicker } from "./ModalFilePicker";
18
16
 
19
17
  /** A boolean choice's answers, as the portal spells them. */
20
18
  const YES_NO = [
@@ -35,55 +33,50 @@ type Props = {
35
33
  * takes the keyboard on open.
36
34
  */
37
35
  export const FileChooserDialog = ({ answer, body, folders, screen }: Props) => {
38
- const region = useScreenRegion(screen);
39
36
  const [choices, setChoices] = useState<ReadonlyMap<string, string>>(
40
37
  () => new Map(body.choices.map((choice) => [choice.id, choice.initial])),
41
38
  );
42
39
  return (
43
- <div className={regionStyles} style={region}>
44
- <FilePicker
45
- ref={focusOnAttach}
46
- request={{
47
- accept: [],
48
- acceptLabel: body.acceptLabel ?? acceptOf(body.mode),
49
- cancel: () => {
50
- answer(Answer.Canceled());
51
- },
52
- choose: (paths, filter) => {
53
- answer(
54
- Answer.FileChooser({ choices, currentFilter: filter, paths }),
55
- );
56
- },
57
- controls: (
58
- <>
59
- {body.mode === FileChooserMode.SaveFiles && (
60
- <span
61
- className={savesStyles}
62
- >{`Saves ${body.files.join(", ")}`}</span>
63
- )}
64
- {body.choices.map((choice) => (
65
- <Choice
66
- choice={choice}
67
- key={choice.id}
68
- onChange={(value) => {
69
- setChoices(new Map(choices).set(choice.id, value));
70
- }}
71
- value={choices.get(choice.id)}
72
- />
73
- ))}
74
- </>
75
- ),
76
- currentFilter: body.currentFilter,
77
- currentFolder: body.currentFolder,
78
- filters: body.filters.length === 0 ? undefined : body.filters,
79
- folders,
80
- home: body.home,
81
- mode: chooserModeOf(body),
82
- suggestedName: body.currentName ?? "",
83
- title: body.title,
84
- }}
85
- />
86
- </div>
40
+ <ModalFilePicker
41
+ request={{
42
+ accept: [],
43
+ acceptLabel: body.acceptLabel ?? acceptOf(body.mode),
44
+ cancel: () => {
45
+ answer(Answer.Canceled());
46
+ },
47
+ choose: (paths, filter) => {
48
+ answer(Answer.FileChooser({ choices, currentFilter: filter, paths }));
49
+ },
50
+ controls: (
51
+ <>
52
+ {body.mode === FileChooserMode.SaveFiles && (
53
+ <span
54
+ className={savesStyles}
55
+ >{`Saves ${body.files.join(", ")}`}</span>
56
+ )}
57
+ {body.choices.map((choice) => (
58
+ <Choice
59
+ choice={choice}
60
+ key={choice.id}
61
+ onChange={(value) => {
62
+ setChoices(new Map(choices).set(choice.id, value));
63
+ }}
64
+ value={choices.get(choice.id)}
65
+ />
66
+ ))}
67
+ </>
68
+ ),
69
+ currentFilter: body.currentFilter,
70
+ currentFolder: body.currentFolder,
71
+ filters: body.filters.length === 0 ? undefined : body.filters,
72
+ folders,
73
+ home: body.home,
74
+ mode: chooserModeOf(body),
75
+ suggestedName: body.currentName ?? "",
76
+ title: body.title,
77
+ }}
78
+ screen={screen}
79
+ />
87
80
  );
88
81
  };
89
82
 
@@ -116,11 +109,6 @@ const Choice = ({
116
109
  />
117
110
  );
118
111
 
119
- const regionStyles = css({
120
- inset: 0,
121
- position: "fixed",
122
- });
123
-
124
112
  const savesStyles = css({ color: "muted", fontSize: "sm" });
125
113
 
126
114
  /** The picker's mode for what the application asked. */
@@ -0,0 +1,52 @@
1
+ import { Dialog as BaseDialog } from "@base-ui/react/dialog";
2
+ import { useRef } from "react";
3
+ import { css } from "../../styled-system/css";
4
+ import { FilePicker } from "../FilePicker/FilePicker";
5
+ import type { FileRequest } from "../FilePicker/file-request";
6
+ import { useScreenRegion } from "../Screen/DisplayProvider";
7
+
8
+ type Props = {
9
+ request: FileRequest;
10
+ /** The display to cover. Without it, the whole page. */
11
+ screen: string | undefined;
12
+ };
13
+
14
+ /**
15
+ * A `FilePicker` over `screen`, modal like `ModalDialog`: in a portal at the
16
+ * dialogs' depth, with the rest of the page inert. Its box takes the keyboard
17
+ * on open.
18
+ *
19
+ * The picker answers every key and press itself, Escape included, so the
20
+ * dialog never closes on its own.
21
+ */
22
+ export const ModalFilePicker = ({ request, screen }: Props) => {
23
+ const region = useScreenRegion(screen);
24
+ const box = useRef<HTMLInputElement>(null);
25
+ return (
26
+ <BaseDialog.Root onOpenChange={stayOpen} open>
27
+ <BaseDialog.Portal>
28
+ {/* The picker is the dialog; this box only places it. */}
29
+ <BaseDialog.Popup
30
+ className={regionStyles}
31
+ initialFocus={box}
32
+ role="presentation"
33
+ style={region}
34
+ >
35
+ <FilePicker ref={box} request={request} />
36
+ </BaseDialog.Popup>
37
+ </BaseDialog.Portal>
38
+ </BaseDialog.Root>
39
+ );
40
+ };
41
+
42
+ /** Ignores base-ui's requests to close; see {@link ModalFilePicker}. */
43
+ const stayOpen = () => {
44
+ // The picker cancels through its request.
45
+ };
46
+
47
+ // At the other dialogs' depth, over every window.
48
+ const regionStyles = css({
49
+ inset: 0,
50
+ position: "fixed",
51
+ zIndex: "modal",
52
+ });
@@ -17,16 +17,14 @@ import { PrinterIcon } from "@phosphor-icons/react/dist/ssr/Printer";
17
17
  import { useState } from "react";
18
18
  import { css } from "../../styled-system/css";
19
19
  import { grid } from "../../styled-system/patterns";
20
- import { focusOnAttach } from "../_control/focusOnAttach";
21
20
  import { Button } from "../Button/Button";
22
21
  import { Field } from "../Field/Field";
23
- import { FilePicker } from "../FilePicker/FilePicker";
24
22
  import { ChooserMode } from "../FilePicker/file-request";
25
23
  import type { Folders } from "../FilePicker/folders";
26
24
  import { Input } from "../Input/Input";
27
25
  import { ModalDialog } from "../ModalDialog/ModalDialog";
28
- import { useScreenRegion } from "../Screen/DisplayProvider";
29
26
  import { Select } from "../Select/Select";
27
+ import { ModalFilePicker } from "./ModalFilePicker";
30
28
  import { pageRanges } from "./page-ranges";
31
29
 
32
30
  const SIDES = {
@@ -351,33 +349,28 @@ const PdfPicker = ({
351
349
  folders: Folders;
352
350
  options: PrintOptions;
353
351
  screen: string | undefined;
354
- }) => {
355
- const region = useScreenRegion(screen);
356
- return (
357
- <div className={regionStyles} style={region}>
358
- <FilePicker
359
- ref={focusOnAttach}
360
- request={{
361
- accept: ["pdf"],
362
- acceptLabel: "Save",
363
- cancel: back,
364
- choose: ([path]) => {
365
- if (path === undefined) {
366
- throw new Error("a save chose no file");
367
- } else {
368
- answer(Answer.SaveToPdf(path, options));
369
- }
370
- },
371
- folders,
372
- home: body.home,
373
- mode: ChooserMode.Save,
374
- suggestedName: pdfName(body.title),
375
- title: "Save as PDF",
376
- }}
377
- />
378
- </div>
379
- );
380
- };
352
+ }) => (
353
+ <ModalFilePicker
354
+ request={{
355
+ accept: ["pdf"],
356
+ acceptLabel: "Save",
357
+ cancel: back,
358
+ choose: ([path]) => {
359
+ if (path === undefined) {
360
+ throw new Error("a save chose no file");
361
+ } else {
362
+ answer(Answer.SaveToPdf(path, options));
363
+ }
364
+ },
365
+ folders,
366
+ home: body.home,
367
+ mode: ChooserMode.Save,
368
+ suggestedName: pdfName(body.title),
369
+ title: "Save as PDF",
370
+ }}
371
+ screen={screen}
372
+ />
373
+ );
381
374
 
382
375
  const askerStyles = css({ color: "muted", fontSize: "sm", margin: 0 });
383
376
 
@@ -403,11 +396,6 @@ const pagesStyles = grid({
403
396
  gridColumn: "1 / -1",
404
397
  });
405
398
 
406
- const regionStyles = css({
407
- inset: 0,
408
- position: "fixed",
409
- });
410
-
411
399
  /** `printer` for people. */
412
400
  const nameOf = (printer: Printer): string =>
413
401
  printer.description ?? printer.name;