@eifi1/ui-kit 0.15.4 → 0.15.5

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.
Files changed (98) hide show
  1. package/README.md +5 -5
  2. package/dist/chart.d.ts +2 -3
  3. package/dist/components/alert-banner.js +1 -1
  4. package/dist/components/alert-banner.js.map +1 -1
  5. package/dist/components/amount-input.d.ts +5 -3
  6. package/dist/components/amount-input.js +1 -1
  7. package/dist/components/amount-input.js.map +1 -1
  8. package/dist/components/button-group.d.ts +2 -3
  9. package/dist/components/calculator.d.ts +2 -3
  10. package/dist/components/checkbox.js +1 -1
  11. package/dist/components/checkbox.js.map +1 -1
  12. package/dist/components/choice-card.js +1 -1
  13. package/dist/components/choice-card.js.map +1 -1
  14. package/dist/components/copy-button.d.ts +2 -3
  15. package/dist/components/error-boundary.js +1 -1
  16. package/dist/components/error-boundary.js.map +1 -1
  17. package/dist/components/facing-pair.d.ts +2 -3
  18. package/dist/components/file-button.d.ts +2 -3
  19. package/dist/components/file-dropzone.d.ts +2 -3
  20. package/dist/components/file-dropzone.js +1 -1
  21. package/dist/components/file-dropzone.js.map +1 -1
  22. package/dist/components/form-actions.d.ts +2 -3
  23. package/dist/components/money-field.d.ts +2 -3
  24. package/dist/components/number-field.d.ts +2 -3
  25. package/dist/components/number-input.d.ts +2 -3
  26. package/dist/components/numpad-sheet.d.ts +2 -3
  27. package/dist/components/series-chart.d.ts +2 -3
  28. package/dist/components/settings-fields.d.ts +2 -3
  29. package/dist/components/text-link.d.ts +2 -3
  30. package/dist/components/time-input.d.ts +2 -3
  31. package/dist/components/ui.d.ts +2 -3
  32. package/dist/components/ui.js +7 -7
  33. package/dist/components/ui.js.map +1 -1
  34. package/dist/feedback/feedback-attachment.d.ts +2 -82
  35. package/dist/feedback/feedback-attachment.js +271 -54
  36. package/dist/feedback/feedback-attachment.js.map +1 -1
  37. package/dist/feedback/feedback-dialog.d.ts +2 -105
  38. package/dist/feedback/feedback-dialog.js +56 -25
  39. package/dist/feedback/feedback-dialog.js.map +1 -1
  40. package/dist/feedback/feedback-inbox.d.ts +1 -1
  41. package/dist/feedback/feedback-thread.d.ts +2 -2
  42. package/dist/feedback-attachment-BYAHJMOr.d.ts +289 -0
  43. package/dist/feedback.d.ts +1 -2
  44. package/dist/hooks/use-file-drop.d.ts +2 -3
  45. package/dist/i18n/defaults.d.ts +2 -3
  46. package/dist/i18n/kit-labels.d.ts +2 -3
  47. package/dist/i18n/locales/de-CH-informal.d.ts +2 -3
  48. package/dist/i18n/locales/de-CH.d.ts +2 -3
  49. package/dist/i18n/locales/de-informal.d.ts +2 -3
  50. package/dist/i18n/locales/de.d.ts +2 -3
  51. package/dist/i18n/locales/de.js +5 -1
  52. package/dist/i18n/locales/de.js.map +1 -1
  53. package/dist/i18n/locales/es.d.ts +2 -3
  54. package/dist/i18n/locales/es.js +5 -1
  55. package/dist/i18n/locales/es.js.map +1 -1
  56. package/dist/i18n/locales/fr.d.ts +2 -3
  57. package/dist/i18n/locales/fr.js +5 -1
  58. package/dist/i18n/locales/fr.js.map +1 -1
  59. package/dist/i18n/locales/hu.d.ts +2 -3
  60. package/dist/i18n/locales/hu.js +5 -1
  61. package/dist/i18n/locales/hu.js.map +1 -1
  62. package/dist/i18n/locales/it.d.ts +2 -3
  63. package/dist/i18n/locales/it.js +5 -1
  64. package/dist/i18n/locales/it.js.map +1 -1
  65. package/dist/i18n/locales/zh.d.ts +2 -3
  66. package/dist/i18n/locales/zh.js +5 -1
  67. package/dist/i18n/locales/zh.js.map +1 -1
  68. package/dist/index.d.ts +2 -3
  69. package/dist/{kit-labels-CnnBd-2N.d.ts → kit-labels-BD2F7sOz.d.ts} +2 -3
  70. package/dist/rhf/fields.d.ts +2 -3
  71. package/dist/rhf/form.d.ts +2 -3
  72. package/dist/rhf.d.ts +2 -3
  73. package/dist/shell/app-shell.d.ts +2 -3
  74. package/dist/shell/top-bar-brand.d.ts +2 -3
  75. package/dist/shell.d.ts +2 -3
  76. package/dist/theme/palette-derive.d.ts +3 -0
  77. package/dist/theme/palette-derive.js +7 -0
  78. package/dist/theme/palette-derive.js.map +1 -1
  79. package/dist/wizard/stepper-nav.d.ts +2 -3
  80. package/dist/wizard.d.ts +2 -3
  81. package/package.json +4 -2
  82. package/src/components/alert-banner.tsx +1 -1
  83. package/src/components/amount-input.tsx +8 -1
  84. package/src/components/checkbox.tsx +1 -1
  85. package/src/components/choice-card.tsx +1 -1
  86. package/src/components/error-boundary.tsx +1 -1
  87. package/src/components/file-dropzone.tsx +1 -1
  88. package/src/components/ui.tsx +7 -7
  89. package/src/feedback/feedback-attachment.tsx +441 -96
  90. package/src/feedback/feedback-dialog.tsx +147 -50
  91. package/src/i18n/locales/de.ts +4 -0
  92. package/src/i18n/locales/es.ts +4 -0
  93. package/src/i18n/locales/fr.ts +4 -0
  94. package/src/i18n/locales/hu.ts +4 -0
  95. package/src/i18n/locales/it.ts +4 -0
  96. package/src/i18n/locales/zh.ts +4 -0
  97. package/src/theme/palette-derive.ts +10 -0
  98. package/tokens.css +9 -1
@@ -1,105 +1,2 @@
1
- import * as react from 'react';
2
- import { ReactNode } from 'react';
3
-
4
- interface FeedbackCategoryOption {
5
- value: string;
6
- label: string;
7
- }
8
- interface FeedbackAttachmentLabels {
9
- /** The heading over the field. Optional: a note editor puts the buttons
10
- * straight under its textarea, where a second heading is noise. */
11
- attachment?: string;
12
- attachmentAdd: string;
13
- /** Label for the "capture screenshot" button. Optional — falls back to the provider's
14
- * `feedbackAttachment.attachmentCapture`, then English. */
15
- attachmentCapture?: string;
16
- /** The line under the attachment buttons saying a screenshot can be pasted
17
- * straight in. Optional — falls back to the provider's `feedbackAttachment`, then English. */
18
- attachmentPaste?: string;
19
- attachmentRemove: string;
20
- }
21
- interface FeedbackDialogLabels extends FeedbackAttachmentLabels {
22
- title: string;
23
- category: string;
24
- subject: string;
25
- body: string;
26
- attachment: string;
27
- submitHint: string;
28
- cancel: string;
29
- save: string;
30
- }
31
- /**
32
- * The dialog's own strings — the `feedbackDialog` namespace of `<UiKitProvider
33
- * labels>` (0.12.0). The attachment keys are not repeated here: they are the
34
- * `feedbackAttachment` namespace's, which the field inside already reads.
35
- *
36
- * Before, every key was required at the call site, so each app restated ten strings
37
- * wherever it mounted the dialog (kastlan feedback-button.tsx built the object inline).
38
- */
39
- interface FeedbackDialogTextLabels {
40
- title: string;
41
- category: string;
42
- subject: string;
43
- body: string;
44
- /** The body's label when `requireBody={false}`: "What happened? (optional)".
45
- * Optional, so a complete `UiKitLabels` typed before 0.14.2 still compiles. */
46
- bodyOptional?: string;
47
- /** The heading over the attachment buttons. */
48
- attachment: string;
49
- /** The line beside the buttons naming the shortcut. */
50
- submitHint: string;
51
- cancel: string;
52
- save: string;
53
- }
54
- declare const DEFAULT_FEEDBACK_DIALOG_LABELS: FeedbackDialogTextLabels;
55
- interface FeedbackSubmission {
56
- title: string;
57
- body: string;
58
- category: string;
59
- attachment: File | null;
60
- }
61
- /**
62
- * The generic feedback form dialog: category + subject + body + an optional image
63
- * attachment, with Ctrl/Cmd+Enter to submit. Domain-free — the app supplies the
64
- * category options, labels and an `onSubmit` that talks to its own backend, plus
65
- * an optional `contextSlot` for app-specific context (user, current URL, …).
66
- *
67
- * **A screenshot can be pasted straight in.** Ctrl/Cmd+V anywhere in the dialog
68
- * takes an image off the clipboard and makes it the attachment, through the same
69
- * validation and the same preview as the file picker. It is the gesture the two
70
- * ways in did not cover: `onCaptureScreenshot` snapshots the *whole* app view,
71
- * and the file picker needs a file — so somebody who wanted to show one panel,
72
- * or one region of one, had to save a crop to disk first and then find it again
73
- * (Steering Design feedback #39). The clipboard is where a region snip already
74
- * is on every platform.
75
- */
76
- declare function FeedbackDialog({ open, onClose, categories, category, onCategoryChange, labels: labelsProp, onSubmit, submitting, contextSlot, attachmentAccept, maxAttachmentBytes, onAttachmentError, onCaptureScreenshot, requireBody, }: {
77
- open: boolean;
78
- onClose: () => void;
79
- categories: FeedbackCategoryOption[];
80
- category: string;
81
- onCategoryChange: (value: string) => void;
82
- /** Prop > `<UiKitProvider labels={{ feedbackDialog, feedbackAttachment }}>` >
83
- * English. Optional since 0.12.0; a whole `FeedbackDialogLabels` still fits. */
84
- labels?: Partial<FeedbackDialogLabels>;
85
- onSubmit: (data: FeedbackSubmission) => void | Promise<void>;
86
- submitting?: boolean;
87
- contextSlot?: ReactNode;
88
- attachmentAccept?: string[];
89
- maxAttachmentBytes?: number;
90
- onAttachmentError?: (kind: "type" | "size") => void;
91
- /**
92
- * Optional: capture a screenshot of the underlying app view and return it as a
93
- * File. When provided, a "Capture screenshot" button is shown next to "Add
94
- * attachment"; the returned file is fed through the same validation + preview.
95
- */
96
- onCaptureScreenshot?: () => Promise<File | null>;
97
- /**
98
- * `false`: a report with only a subject can be sent, and the body's label says it is
99
- * optional (`bodyOptional`, unless `labels.body` is passed). Default `true`, the
100
- * dialog's behaviour until 0.14.2 (keksdose K1: its backend takes title-only reports).
101
- */
102
- requireBody?: boolean;
103
- }): react.JSX.Element | null;
104
-
105
- export { DEFAULT_FEEDBACK_DIALOG_LABELS, type FeedbackAttachmentLabels, type FeedbackCategoryOption, FeedbackDialog, type FeedbackDialogLabels, type FeedbackDialogTextLabels, type FeedbackSubmission };
1
+ import 'react';
2
+ export { b as DEFAULT_FEEDBACK_DIALOG_LABELS, j as FeedbackAttachmentLabels, k as FeedbackCategoryOption, l as FeedbackDialog, m as FeedbackDialogLabels, n as FeedbackDialogMultipleProps, o as FeedbackDialogProps, p as FeedbackDialogSingleProps, q as FeedbackDialogTextLabels, r as FeedbackMultipleSubmission, s as FeedbackSubmission } from '../feedback-attachment-BYAHJMOr.js';
@@ -17,32 +17,37 @@ const DEFAULT_FEEDBACK_DIALOG_LABELS = {
17
17
  body: "What happened?",
18
18
  bodyOptional: "What happened? (optional)",
19
19
  attachment: "Screenshot",
20
+ attachments: "Attachments",
20
21
  submitHint: "Ctrl/\u2318 + Enter to send",
21
22
  cancel: "Cancel",
22
23
  save: "Send"
23
24
  };
24
- function FeedbackDialog({
25
- open,
26
- onClose,
27
- categories,
28
- category,
29
- onCategoryChange,
30
- labels: labelsProp,
31
- onSubmit,
32
- submitting = false,
33
- contextSlot,
34
- attachmentAccept = DEFAULT_ATTACHMENT_ACCEPT,
35
- maxAttachmentBytes = DEFAULT_MAX_ATTACHMENT_BYTES,
36
- onAttachmentError,
37
- onCaptureScreenshot,
38
- requireBody = true
39
- }) {
25
+ function FeedbackDialog(props) {
26
+ const {
27
+ open,
28
+ onClose,
29
+ categories,
30
+ category,
31
+ onCategoryChange,
32
+ labels: labelsProp,
33
+ submitting = false,
34
+ contextSlot,
35
+ attachmentAccept = DEFAULT_ATTACHMENT_ACCEPT,
36
+ maxAttachmentBytes = DEFAULT_MAX_ATTACHMENT_BYTES,
37
+ onCaptureScreenshot,
38
+ requireBody = true
39
+ } = props;
40
40
  const [title, setTitle] = useState("");
41
41
  const [body, setBody] = useState("");
42
42
  const [attachment, setAttachment] = useState(null);
43
+ const [screenshot, setScreenshot] = useState(null);
44
+ const [files, setFiles] = useState([]);
43
45
  const isMobile = useMediaQuery(PHONE_QUERY, false);
44
46
  const labels = useKitLabels("feedbackDialog", DEFAULT_FEEDBACK_DIALOG_LABELS, labelsProp);
45
- const attachmentLabels = { ...labelsProp, attachment: labels.attachment };
47
+ const attachmentLabels = {
48
+ ...labelsProp,
49
+ attachment: props.attachments === "multiple" ? labels.attachments ?? DEFAULT_FEEDBACK_DIALOG_LABELS.attachments : labels.attachment
50
+ };
46
51
  const [wasOpen, setWasOpen] = useState(open);
47
52
  if (open !== wasOpen) {
48
53
  setWasOpen(open);
@@ -50,11 +55,18 @@ function FeedbackDialog({
50
55
  setTitle("");
51
56
  setBody("");
52
57
  setAttachment(null);
58
+ setScreenshot(null);
59
+ setFiles([]);
53
60
  }
54
61
  }
55
62
  const canSubmit = !!title.trim() && (!requireBody || !!body.trim()) && !submitting;
56
63
  const trySubmit = () => {
57
- if (canSubmit) void onSubmit({ title, body, category, attachment });
64
+ if (!canSubmit) return;
65
+ if (props.attachments === "multiple") {
66
+ void props.onSubmit({ title, body, category, screenshot, attachments: files });
67
+ } else {
68
+ void props.onSubmit({ title, body, category, attachment });
69
+ }
58
70
  };
59
71
  if (!open) return null;
60
72
  const categoryField = /* @__PURE__ */ jsx(Select, { label: labels.category, value: category, onChange: (e) => onCategoryChange(e.target.value), children: categories.map((c) => /* @__PURE__ */ jsx("option", { value: c.value, children: c.label }, c.value)) });
@@ -68,17 +80,36 @@ function FeedbackDialog({
68
80
  onChange: (e) => setBody(e.target.value)
69
81
  }
70
82
  );
71
- const attachmentField = /* @__PURE__ */ jsx(
83
+ const fieldProps = {
84
+ labels: attachmentLabels,
85
+ accept: attachmentAccept,
86
+ maxBytes: maxAttachmentBytes,
87
+ onCaptureScreenshot,
88
+ // On `document`, not on the panel: the Modal focuses its own panel on open
89
+ // and traps Tab inside it, so while this dialog is up every paste in the
90
+ // page is meant for it — including the one made with nothing in
91
+ // particular focused, which never reaches a React `onPaste` on a child.
92
+ documentPaste: open
93
+ };
94
+ const attachmentField = props.attachments === "multiple" ? /* @__PURE__ */ jsx(
95
+ FeedbackAttachmentField,
96
+ {
97
+ ...fieldProps,
98
+ multiple: true,
99
+ value: files,
100
+ onChange: setFiles,
101
+ max: props.maxAttachments,
102
+ screenshot,
103
+ onScreenshotChange: setScreenshot,
104
+ onError: props.onAttachmentError
105
+ }
106
+ ) : /* @__PURE__ */ jsx(
72
107
  FeedbackAttachmentField,
73
108
  {
109
+ ...fieldProps,
74
110
  value: attachment,
75
111
  onChange: setAttachment,
76
- labels: attachmentLabels,
77
- accept: attachmentAccept,
78
- maxBytes: maxAttachmentBytes,
79
- onError: onAttachmentError,
80
- onCaptureScreenshot,
81
- documentPaste: open
112
+ onError: props.onAttachmentError
82
113
  }
83
114
  );
84
115
  return /* @__PURE__ */ jsxs(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/feedback/feedback-dialog.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Button, Input, PHONE_QUERY, Select, Textarea } from \"../components/ui\";\nimport { Modal } from \"../components/modal\";\nimport { useMediaQuery } from \"../hooks/use-media-query\";\nimport { useKitLabels } from \"../i18n/kit-labels\";\nimport {\n DEFAULT_ATTACHMENT_ACCEPT,\n DEFAULT_MAX_ATTACHMENT_BYTES,\n FeedbackAttachmentField,\n} from \"./feedback-attachment\";\n\nexport interface FeedbackCategoryOption {\n value: string;\n label: string;\n}\n\nexport interface FeedbackAttachmentLabels {\n /** The heading over the field. Optional: a note editor puts the buttons\n * straight under its textarea, where a second heading is noise. */\n attachment?: string;\n attachmentAdd: string;\n /** Label for the \"capture screenshot\" button. Optional — falls back to the provider's\n * `feedbackAttachment.attachmentCapture`, then English. */\n attachmentCapture?: string;\n /** The line under the attachment buttons saying a screenshot can be pasted\n * straight in. Optional — falls back to the provider's `feedbackAttachment`, then English. */\n attachmentPaste?: string;\n attachmentRemove: string;\n}\n\nexport interface FeedbackDialogLabels extends FeedbackAttachmentLabels {\n title: string;\n category: string;\n subject: string;\n body: string;\n attachment: string;\n submitHint: string;\n cancel: string;\n save: string;\n}\n\n/**\n * The dialog's own strings — the `feedbackDialog` namespace of `<UiKitProvider\n * labels>` (0.12.0). The attachment keys are not repeated here: they are the\n * `feedbackAttachment` namespace's, which the field inside already reads.\n *\n * Before, every key was required at the call site, so each app restated ten strings\n * wherever it mounted the dialog (kastlan feedback-button.tsx built the object inline).\n */\nexport interface FeedbackDialogTextLabels {\n title: string;\n category: string;\n subject: string;\n body: string;\n /** The body's label when `requireBody={false}`: \"What happened? (optional)\".\n * Optional, so a complete `UiKitLabels` typed before 0.14.2 still compiles. */\n bodyOptional?: string;\n /** The heading over the attachment buttons. */\n attachment: string;\n /** The line beside the buttons naming the shortcut. */\n submitHint: string;\n cancel: string;\n save: string;\n}\n\nexport const DEFAULT_FEEDBACK_DIALOG_LABELS: FeedbackDialogTextLabels = {\n title: \"Send feedback\",\n category: \"Category\",\n subject: \"Subject\",\n body: \"What happened?\",\n bodyOptional: \"What happened? (optional)\",\n attachment: \"Screenshot\",\n submitHint: \"Ctrl/⌘ + Enter to send\",\n cancel: \"Cancel\",\n save: \"Send\",\n};\n\nexport interface FeedbackSubmission {\n title: string;\n body: string;\n category: string;\n attachment: File | null;\n}\n\n/**\n * The generic feedback form dialog: category + subject + body + an optional image\n * attachment, with Ctrl/Cmd+Enter to submit. Domain-free — the app supplies the\n * category options, labels and an `onSubmit` that talks to its own backend, plus\n * an optional `contextSlot` for app-specific context (user, current URL, …).\n *\n * **A screenshot can be pasted straight in.** Ctrl/Cmd+V anywhere in the dialog\n * takes an image off the clipboard and makes it the attachment, through the same\n * validation and the same preview as the file picker. It is the gesture the two\n * ways in did not cover: `onCaptureScreenshot` snapshots the *whole* app view,\n * and the file picker needs a file — so somebody who wanted to show one panel,\n * or one region of one, had to save a crop to disk first and then find it again\n * (Steering Design feedback #39). The clipboard is where a region snip already\n * is on every platform.\n */\nexport function FeedbackDialog({\n open,\n onClose,\n categories,\n category,\n onCategoryChange,\n labels: labelsProp,\n onSubmit,\n submitting = false,\n contextSlot,\n attachmentAccept = DEFAULT_ATTACHMENT_ACCEPT,\n maxAttachmentBytes = DEFAULT_MAX_ATTACHMENT_BYTES,\n onAttachmentError,\n onCaptureScreenshot,\n requireBody = true,\n}: {\n open: boolean;\n onClose: () => void;\n categories: FeedbackCategoryOption[];\n category: string;\n onCategoryChange: (value: string) => void;\n /** Prop > `<UiKitProvider labels={{ feedbackDialog, feedbackAttachment }}>` >\n * English. Optional since 0.12.0; a whole `FeedbackDialogLabels` still fits. */\n labels?: Partial<FeedbackDialogLabels>;\n onSubmit: (data: FeedbackSubmission) => void | Promise<void>;\n submitting?: boolean;\n contextSlot?: ReactNode;\n attachmentAccept?: string[];\n maxAttachmentBytes?: number;\n onAttachmentError?: (kind: \"type\" | \"size\") => void;\n /**\n * Optional: capture a screenshot of the underlying app view and return it as a\n * File. When provided, a \"Capture screenshot\" button is shown next to \"Add\n * attachment\"; the returned file is fed through the same validation + preview.\n */\n onCaptureScreenshot?: () => Promise<File | null>;\n /**\n * `false`: a report with only a subject can be sent, and the body's label says it is\n * optional (`bodyOptional`, unless `labels.body` is passed). Default `true`, the\n * dialog's behaviour until 0.14.2 (keksdose K1: its backend takes title-only reports).\n */\n requireBody?: boolean;\n}) {\n const [title, setTitle] = useState(\"\");\n const [body, setBody] = useState(\"\");\n const [attachment, setAttachment] = useState<File | null>(null);\n const isMobile = useMediaQuery(PHONE_QUERY, false);\n const labels = useKitLabels(\"feedbackDialog\", DEFAULT_FEEDBACK_DIALOG_LABELS, labelsProp);\n // The attachment field resolves its own keys from `feedbackAttachment`; it gets the\n // prop's (so a caller's `attachmentAdd` still wins) plus the resolved heading.\n const attachmentLabels = { ...labelsProp, attachment: labels.attachment };\n\n // Reset the form whenever the dialog is (re)opened — during render, on the\n // closed-to-open transition, so the old draft never paints for a frame.\n const [wasOpen, setWasOpen] = useState(open);\n if (open !== wasOpen) {\n setWasOpen(open);\n if (open) {\n setTitle(\"\");\n setBody(\"\");\n setAttachment(null);\n }\n }\n\n // Trimmed: a subject or body of spaces is empty (keksdose's API answers a blank title\n // with a 422, and a blank report is no report).\n const canSubmit = !!title.trim() && (!requireBody || !!body.trim()) && !submitting;\n const trySubmit = () => {\n if (canSubmit) void onSubmit({ title, body, category, attachment });\n };\n\n if (!open) return null;\n\n const categoryField = (\n <Select label={labels.category} value={category} onChange={(e) => onCategoryChange(e.target.value)}>\n {categories.map((c) => (\n <option key={c.value} value={c.value}>\n {c.label}\n </option>\n ))}\n </Select>\n );\n // On a phone the subject leads as a heading rather than as the second of two\n // identical boxes under a select (Keksdose feedback #179). `variant=\"display\"`\n // is a no-op above the phone breakpoint, so the desktop dialog is unchanged.\n const subjectField = (\n <Input label={labels.subject} value={title} onChange={(e) => setTitle(e.target.value)} variant=\"display\" />\n );\n const bodyField = (\n <Textarea\n rows={5}\n label={requireBody ? labels.body : (labelsProp?.body ?? labels.bodyOptional ?? labels.body)}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n />\n );\n const attachmentField = (\n <FeedbackAttachmentField\n value={attachment}\n onChange={setAttachment}\n labels={attachmentLabels}\n accept={attachmentAccept}\n maxBytes={maxAttachmentBytes}\n onError={onAttachmentError}\n onCaptureScreenshot={onCaptureScreenshot}\n // On `document`, not on the panel: the Modal focuses its own panel on open\n // and traps Tab inside it, so while this dialog is up every paste in the\n // page is meant for it — including the one made with nothing in\n // particular focused, which never reaches a React `onPaste` on a child.\n documentPaste={open}\n />\n );\n\n return (\n <Modal\n onClose={onClose}\n // The one dialog whose subject is the page behind it (Keksdose dev#460: \"Make\n // the feedback dialog draggable so I can see behind it if it blocks\n // something\") — you are describing what is under it while you type.\n draggable\n onKeyDown={(e) => {\n if ((e.ctrlKey || e.metaKey) && e.key === \"Enter\") {\n e.preventDefault();\n trySubmit();\n }\n }}\n >\n {/* Also the drag handle: pressing anywhere on the panel's own chrome moves it,\n and the heading is the strip a user reaches for. */}\n <h2 className=\"mb-3 text-lg font-semibold\">{labels.title}</h2>\n <div className=\"space-y-3\">\n {isMobile ? (\n // Phone shape, the same reasoning as the transaction editor's (#177):\n // the desktop order is the DATA MODEL's order — category, then subject,\n // then body — but nobody opens this dialog to pick a category. What they\n // came to do is say the thing, so that leads; the classification and the\n // evidence follow, a tier down.\n <>\n {subjectField}\n {bodyField}\n <div className=\"space-y-3 border-t border-[var(--border)] pt-3\">\n {categoryField}\n {attachmentField}\n {contextSlot}\n </div>\n </>\n ) : (\n <>\n {categoryField}\n {subjectField}\n {bodyField}\n {attachmentField}\n {contextSlot}\n </>\n )}\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"text-xs text-[var(--text-placeholder)]\">{labels.submitHint}</div>\n <div className=\"flex gap-2\">\n <Button variant=\"ghost\" onClick={onClose}>\n {labels.cancel}\n </Button>\n <Button onClick={trySubmit} disabled={!canSubmit}>\n {labels.save}\n </Button>\n </div>\n </div>\n </div>\n </Modal>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/feedback/feedback-dialog.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Button, Input, PHONE_QUERY, Select, Textarea } from \"../components/ui\";\nimport { Modal } from \"../components/modal\";\nimport { useMediaQuery } from \"../hooks/use-media-query\";\nimport { useKitLabels } from \"../i18n/kit-labels\";\nimport {\n DEFAULT_ATTACHMENT_ACCEPT,\n DEFAULT_MAX_ATTACHMENT_BYTES,\n FeedbackAttachmentField,\n type FeedbackAttachmentError,\n} from \"./feedback-attachment\";\n\nexport interface FeedbackCategoryOption {\n value: string;\n label: string;\n}\n\nexport interface FeedbackAttachmentLabels {\n /** The heading over the field. Optional: a note editor puts the buttons\n * straight under its textarea, where a second heading is noise. */\n attachment?: string;\n attachmentAdd: string;\n /** Label for the \"capture screenshot\" button. Optional — falls back to the provider's\n * `feedbackAttachment.attachmentCapture`, then English. */\n attachmentCapture?: string;\n /** The line under the attachment buttons saying a screenshot can be pasted\n * straight in. Optional — falls back to the provider's `feedbackAttachment`, then English. */\n attachmentPaste?: string;\n attachmentRemove: string;\n /** `multiple` mode (0.15.5): the chip list's accessible name. Optional, as are the\n * two below — they fall back to the provider's `feedbackAttachment`, then English. */\n attachmentList?: string;\n /** `multiple` mode: one chip's remove button, given the file's name. */\n attachmentRemoveFile?: (name: string) => string;\n /** `multiple` mode: the line shown once `max` files are attached. */\n attachmentLimit?: (max: number) => string;\n}\n\nexport interface FeedbackDialogLabels extends FeedbackAttachmentLabels {\n title: string;\n category: string;\n subject: string;\n body: string;\n attachment: string;\n submitHint: string;\n cancel: string;\n save: string;\n /** The heading over the attachments under `attachments=\"multiple\"` (0.15.5), where\n * they are a screenshot AND photos. Optional; falls back to the provider, then English. */\n attachments?: string;\n}\n\n/**\n * The dialog's own strings — the `feedbackDialog` namespace of `<UiKitProvider\n * labels>` (0.12.0). The attachment keys are not repeated here: they are the\n * `feedbackAttachment` namespace's, which the field inside already reads.\n *\n * Before, every key was required at the call site, so each app restated ten strings\n * wherever it mounted the dialog (kastlan feedback-button.tsx built the object inline).\n */\nexport interface FeedbackDialogTextLabels {\n title: string;\n category: string;\n subject: string;\n body: string;\n /** The body's label when `requireBody={false}`: \"What happened? (optional)\".\n * Optional, so a complete `UiKitLabels` typed before 0.14.2 still compiles. */\n bodyOptional?: string;\n /** The heading over the attachment buttons. */\n attachment: string;\n /** The line beside the buttons naming the shortcut. */\n submitHint: string;\n cancel: string;\n save: string;\n /** The heading over the attachments under `attachments=\"multiple\"` (0.15.5).\n * Optional, so a complete `UiKitLabels` typed before 0.15.5 still compiles. */\n attachments?: string;\n}\n\nexport const DEFAULT_FEEDBACK_DIALOG_LABELS: FeedbackDialogTextLabels = {\n title: \"Send feedback\",\n category: \"Category\",\n subject: \"Subject\",\n body: \"What happened?\",\n bodyOptional: \"What happened? (optional)\",\n attachment: \"Screenshot\",\n attachments: \"Attachments\",\n submitHint: \"Ctrl/⌘ + Enter to send\",\n cancel: \"Cancel\",\n save: \"Send\",\n};\n\nexport interface FeedbackSubmission {\n title: string;\n body: string;\n category: string;\n attachment: File | null;\n}\n\n/**\n * What `onSubmit` gets under `attachments=\"multiple\"` (0.15.5): the screenshot and\n * the picked/pasted files apart, because an app files them differently — keksdose\n * attaches the screenshot to the report and the photos as its evidence list. No\n * `attachment`: there is no one file it could name.\n */\nexport interface FeedbackMultipleSubmission {\n title: string;\n body: string;\n category: string;\n /** What `onCaptureScreenshot` returned, or `null` — at most one. */\n screenshot: File | null;\n /** Picked and pasted files, in the order they were added; at most `maxAttachments`. */\n attachments: File[];\n}\n\ninterface FeedbackDialogBaseProps {\n open: boolean;\n onClose: () => void;\n categories: FeedbackCategoryOption[];\n category: string;\n onCategoryChange: (value: string) => void;\n /** Prop > `<UiKitProvider labels={{ feedbackDialog, feedbackAttachment }}>` >\n * English. Optional since 0.12.0; a whole `FeedbackDialogLabels` still fits. */\n labels?: Partial<FeedbackDialogLabels>;\n submitting?: boolean;\n contextSlot?: ReactNode;\n attachmentAccept?: string[];\n maxAttachmentBytes?: number;\n /**\n * Optional: capture a screenshot of the underlying app view and return it as a\n * File. When provided, a \"Capture screenshot\" button is shown next to \"Add\n * attachment\"; the returned file is fed through the same validation + preview.\n */\n onCaptureScreenshot?: () => Promise<File | null>;\n /**\n * `false`: a report with only a subject can be sent, and the body's label says it is\n * optional (`bodyOptional`, unless `labels.body` is passed). Default `true`, the\n * dialog's behaviour until 0.14.2 (keksdose K1: its backend takes title-only reports).\n */\n requireBody?: boolean;\n}\n\n/** One attachment — a screenshot, a picked or a pasted image; a second replaces\n * nothing, it has to wait for the first to be removed. The default. */\nexport interface FeedbackDialogSingleProps extends FeedbackDialogBaseProps {\n attachments?: \"single\";\n onSubmit: (data: FeedbackSubmission) => void | Promise<void>;\n onAttachmentError?: (kind: \"type\" | \"size\") => void;\n /** Multiple mode only — refused here rather than silently ignored. */\n maxAttachments?: never;\n}\n\n/**\n * One screenshot plus up to `maxAttachments` picked or pasted files (0.15.5, keksdose\n * dev#578: \"pasted two photos, the second overwrote the first\"). The capture button is\n * offered while there is no screenshot yet; the add button while there is room.\n */\nexport interface FeedbackDialogMultipleProps extends FeedbackDialogBaseProps {\n attachments: \"multiple\";\n /** Default `DEFAULT_MAX_ATTACHMENTS` (5). The screenshot does not count. */\n maxAttachments?: number;\n onSubmit: (data: FeedbackMultipleSubmission) => void | Promise<void>;\n /** `\"count\"`: more files arrived at once than there was room for; the surplus was dropped. */\n onAttachmentError?: (kind: FeedbackAttachmentError) => void;\n}\n\nexport type FeedbackDialogProps = FeedbackDialogSingleProps | FeedbackDialogMultipleProps;\n\n/**\n * The generic feedback form dialog: category + subject + body + an optional image\n * attachment, with Ctrl/Cmd+Enter to submit. Domain-free — the app supplies the\n * category options, labels and an `onSubmit` that talks to its own backend, plus\n * an optional `contextSlot` for app-specific context (user, current URL, …).\n *\n * **A screenshot can be pasted straight in.** Ctrl/Cmd+V anywhere in the dialog\n * takes an image off the clipboard and makes it the attachment, through the same\n * validation and the same preview as the file picker. It is the gesture the two\n * ways in did not cover: `onCaptureScreenshot` snapshots the *whole* app view,\n * and the file picker needs a file — so somebody who wanted to show one panel,\n * or one region of one, had to save a crop to disk first and then find it again\n * (Steering Design feedback #39). The clipboard is where a region snip already\n * is on every platform.\n *\n * **`attachments=\"multiple\"`** (0.15.5) takes several: every paste and pick adds a\n * chip, and `onSubmit` gets `{ screenshot, attachments }` ({@link\n * FeedbackMultipleSubmission}) instead of `attachment`. Opt-in, so a caller typed\n * against the one-file submission keeps compiling and behaving as before.\n */\nexport function FeedbackDialog(props: FeedbackDialogProps) {\n const {\n open,\n onClose,\n categories,\n category,\n onCategoryChange,\n labels: labelsProp,\n submitting = false,\n contextSlot,\n attachmentAccept = DEFAULT_ATTACHMENT_ACCEPT,\n maxAttachmentBytes = DEFAULT_MAX_ATTACHMENT_BYTES,\n onCaptureScreenshot,\n requireBody = true,\n } = props;\n const [title, setTitle] = useState(\"\");\n const [body, setBody] = useState(\"\");\n const [attachment, setAttachment] = useState<File | null>(null);\n // `attachments=\"multiple\"` only: the capture, apart from the picked/pasted files.\n const [screenshot, setScreenshot] = useState<File | null>(null);\n const [files, setFiles] = useState<File[]>([]);\n const isMobile = useMediaQuery(PHONE_QUERY, false);\n const labels = useKitLabels(\"feedbackDialog\", DEFAULT_FEEDBACK_DIALOG_LABELS, labelsProp);\n // The attachment field resolves its own keys from `feedbackAttachment`; it gets the\n // prop's (so a caller's `attachmentAdd` still wins) plus the resolved heading.\n // Under `multiple` the heading is `attachments` — a screenshot AND photos — unless the\n // caller named the multiple heading themselves.\n const attachmentLabels = {\n ...labelsProp,\n attachment:\n props.attachments === \"multiple\"\n ? (labels.attachments ?? DEFAULT_FEEDBACK_DIALOG_LABELS.attachments)\n : labels.attachment,\n };\n\n // Reset the form whenever the dialog is (re)opened — during render, on the\n // closed-to-open transition, so the old draft never paints for a frame.\n const [wasOpen, setWasOpen] = useState(open);\n if (open !== wasOpen) {\n setWasOpen(open);\n if (open) {\n setTitle(\"\");\n setBody(\"\");\n setAttachment(null);\n setScreenshot(null);\n setFiles([]);\n }\n }\n\n // Trimmed: a subject or body of spaces is empty (keksdose's API answers a blank title\n // with a 422, and a blank report is no report).\n const canSubmit = !!title.trim() && (!requireBody || !!body.trim()) && !submitting;\n const trySubmit = () => {\n if (!canSubmit) return;\n if (props.attachments === \"multiple\") {\n void props.onSubmit({ title, body, category, screenshot, attachments: files });\n } else {\n void props.onSubmit({ title, body, category, attachment });\n }\n };\n\n if (!open) return null;\n\n const categoryField = (\n <Select label={labels.category} value={category} onChange={(e) => onCategoryChange(e.target.value)}>\n {categories.map((c) => (\n <option key={c.value} value={c.value}>\n {c.label}\n </option>\n ))}\n </Select>\n );\n // On a phone the subject leads as a heading rather than as the second of two\n // identical boxes under a select (Keksdose feedback #179). `variant=\"display\"`\n // is a no-op above the phone breakpoint, so the desktop dialog is unchanged.\n const subjectField = (\n <Input label={labels.subject} value={title} onChange={(e) => setTitle(e.target.value)} variant=\"display\" />\n );\n const bodyField = (\n <Textarea\n rows={5}\n label={requireBody ? labels.body : (labelsProp?.body ?? labels.bodyOptional ?? labels.body)}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n />\n );\n const fieldProps = {\n labels: attachmentLabels,\n accept: attachmentAccept,\n maxBytes: maxAttachmentBytes,\n onCaptureScreenshot,\n // On `document`, not on the panel: the Modal focuses its own panel on open\n // and traps Tab inside it, so while this dialog is up every paste in the\n // page is meant for it — including the one made with nothing in\n // particular focused, which never reaches a React `onPaste` on a child.\n documentPaste: open,\n };\n const attachmentField =\n props.attachments === \"multiple\" ? (\n <FeedbackAttachmentField\n {...fieldProps}\n multiple\n value={files}\n onChange={setFiles}\n max={props.maxAttachments}\n // The capture goes to its own slot, so it is offered once and never crowds\n // out a photo; a paste is a photo (a region snip is chosen evidence, not \"the\n // screenshot\").\n screenshot={screenshot}\n onScreenshotChange={setScreenshot}\n onError={props.onAttachmentError}\n />\n ) : (\n <FeedbackAttachmentField\n {...fieldProps}\n value={attachment}\n onChange={setAttachment}\n onError={props.onAttachmentError}\n />\n );\n\n return (\n <Modal\n onClose={onClose}\n // The one dialog whose subject is the page behind it (Keksdose dev#460: \"Make\n // the feedback dialog draggable so I can see behind it if it blocks\n // something\") — you are describing what is under it while you type.\n draggable\n onKeyDown={(e) => {\n if ((e.ctrlKey || e.metaKey) && e.key === \"Enter\") {\n e.preventDefault();\n trySubmit();\n }\n }}\n >\n {/* Also the drag handle: pressing anywhere on the panel's own chrome moves it,\n and the heading is the strip a user reaches for. */}\n <h2 className=\"mb-3 text-lg font-semibold\">{labels.title}</h2>\n <div className=\"space-y-3\">\n {isMobile ? (\n // Phone shape, the same reasoning as the transaction editor's (#177):\n // the desktop order is the DATA MODEL's order — category, then subject,\n // then body — but nobody opens this dialog to pick a category. What they\n // came to do is say the thing, so that leads; the classification and the\n // evidence follow, a tier down.\n <>\n {subjectField}\n {bodyField}\n <div className=\"space-y-3 border-t border-[var(--border)] pt-3\">\n {categoryField}\n {attachmentField}\n {contextSlot}\n </div>\n </>\n ) : (\n <>\n {categoryField}\n {subjectField}\n {bodyField}\n {attachmentField}\n {contextSlot}\n </>\n )}\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"text-xs text-[var(--text-placeholder)]\">{labels.submitHint}</div>\n <div className=\"flex gap-2\">\n <Button variant=\"ghost\" onClick={onClose}>\n {labels.cancel}\n </Button>\n <Button onClick={trySubmit} disabled={!canSubmit}>\n {labels.save}\n </Button>\n </div>\n </div>\n </div>\n </Modal>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { LucideIcon } from 'lucide-react';
4
- import { FeedbackAttachmentLabels } from './feedback-dialog.js';
4
+ import { j as FeedbackAttachmentLabels } from '../feedback-attachment-BYAHJMOr.js';
5
5
 
6
6
  /**
7
7
  * The feedback **inbox**, as the parts two apps were each writing separately.
@@ -1,7 +1,7 @@
1
+ import { j as FeedbackAttachmentLabels } from '../feedback-attachment-BYAHJMOr.js';
2
+ import { FeedbackNoteAttachment } from './feedback-inbox.js';
1
3
  import * as react from 'react';
2
4
  import { ReactNode, Ref } from 'react';
3
- import { FeedbackNoteAttachment } from './feedback-inbox.js';
4
- import { FeedbackAttachmentLabels } from './feedback-dialog.js';
5
5
  import 'lucide-react';
6
6
 
7
7
  /**
@@ -0,0 +1,289 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, RefObject } from 'react';
3
+
4
+ interface FeedbackCategoryOption {
5
+ value: string;
6
+ label: string;
7
+ }
8
+ interface FeedbackAttachmentLabels {
9
+ /** The heading over the field. Optional: a note editor puts the buttons
10
+ * straight under its textarea, where a second heading is noise. */
11
+ attachment?: string;
12
+ attachmentAdd: string;
13
+ /** Label for the "capture screenshot" button. Optional — falls back to the provider's
14
+ * `feedbackAttachment.attachmentCapture`, then English. */
15
+ attachmentCapture?: string;
16
+ /** The line under the attachment buttons saying a screenshot can be pasted
17
+ * straight in. Optional — falls back to the provider's `feedbackAttachment`, then English. */
18
+ attachmentPaste?: string;
19
+ attachmentRemove: string;
20
+ /** `multiple` mode (0.15.5): the chip list's accessible name. Optional, as are the
21
+ * two below — they fall back to the provider's `feedbackAttachment`, then English. */
22
+ attachmentList?: string;
23
+ /** `multiple` mode: one chip's remove button, given the file's name. */
24
+ attachmentRemoveFile?: (name: string) => string;
25
+ /** `multiple` mode: the line shown once `max` files are attached. */
26
+ attachmentLimit?: (max: number) => string;
27
+ }
28
+ interface FeedbackDialogLabels extends FeedbackAttachmentLabels {
29
+ title: string;
30
+ category: string;
31
+ subject: string;
32
+ body: string;
33
+ attachment: string;
34
+ submitHint: string;
35
+ cancel: string;
36
+ save: string;
37
+ /** The heading over the attachments under `attachments="multiple"` (0.15.5), where
38
+ * they are a screenshot AND photos. Optional; falls back to the provider, then English. */
39
+ attachments?: string;
40
+ }
41
+ /**
42
+ * The dialog's own strings — the `feedbackDialog` namespace of `<UiKitProvider
43
+ * labels>` (0.12.0). The attachment keys are not repeated here: they are the
44
+ * `feedbackAttachment` namespace's, which the field inside already reads.
45
+ *
46
+ * Before, every key was required at the call site, so each app restated ten strings
47
+ * wherever it mounted the dialog (kastlan feedback-button.tsx built the object inline).
48
+ */
49
+ interface FeedbackDialogTextLabels {
50
+ title: string;
51
+ category: string;
52
+ subject: string;
53
+ body: string;
54
+ /** The body's label when `requireBody={false}`: "What happened? (optional)".
55
+ * Optional, so a complete `UiKitLabels` typed before 0.14.2 still compiles. */
56
+ bodyOptional?: string;
57
+ /** The heading over the attachment buttons. */
58
+ attachment: string;
59
+ /** The line beside the buttons naming the shortcut. */
60
+ submitHint: string;
61
+ cancel: string;
62
+ save: string;
63
+ /** The heading over the attachments under `attachments="multiple"` (0.15.5).
64
+ * Optional, so a complete `UiKitLabels` typed before 0.15.5 still compiles. */
65
+ attachments?: string;
66
+ }
67
+ declare const DEFAULT_FEEDBACK_DIALOG_LABELS: FeedbackDialogTextLabels;
68
+ interface FeedbackSubmission {
69
+ title: string;
70
+ body: string;
71
+ category: string;
72
+ attachment: File | null;
73
+ }
74
+ /**
75
+ * What `onSubmit` gets under `attachments="multiple"` (0.15.5): the screenshot and
76
+ * the picked/pasted files apart, because an app files them differently — keksdose
77
+ * attaches the screenshot to the report and the photos as its evidence list. No
78
+ * `attachment`: there is no one file it could name.
79
+ */
80
+ interface FeedbackMultipleSubmission {
81
+ title: string;
82
+ body: string;
83
+ category: string;
84
+ /** What `onCaptureScreenshot` returned, or `null` — at most one. */
85
+ screenshot: File | null;
86
+ /** Picked and pasted files, in the order they were added; at most `maxAttachments`. */
87
+ attachments: File[];
88
+ }
89
+ interface FeedbackDialogBaseProps {
90
+ open: boolean;
91
+ onClose: () => void;
92
+ categories: FeedbackCategoryOption[];
93
+ category: string;
94
+ onCategoryChange: (value: string) => void;
95
+ /** Prop > `<UiKitProvider labels={{ feedbackDialog, feedbackAttachment }}>` >
96
+ * English. Optional since 0.12.0; a whole `FeedbackDialogLabels` still fits. */
97
+ labels?: Partial<FeedbackDialogLabels>;
98
+ submitting?: boolean;
99
+ contextSlot?: ReactNode;
100
+ attachmentAccept?: string[];
101
+ maxAttachmentBytes?: number;
102
+ /**
103
+ * Optional: capture a screenshot of the underlying app view and return it as a
104
+ * File. When provided, a "Capture screenshot" button is shown next to "Add
105
+ * attachment"; the returned file is fed through the same validation + preview.
106
+ */
107
+ onCaptureScreenshot?: () => Promise<File | null>;
108
+ /**
109
+ * `false`: a report with only a subject can be sent, and the body's label says it is
110
+ * optional (`bodyOptional`, unless `labels.body` is passed). Default `true`, the
111
+ * dialog's behaviour until 0.14.2 (keksdose K1: its backend takes title-only reports).
112
+ */
113
+ requireBody?: boolean;
114
+ }
115
+ /** One attachment — a screenshot, a picked or a pasted image; a second replaces
116
+ * nothing, it has to wait for the first to be removed. The default. */
117
+ interface FeedbackDialogSingleProps extends FeedbackDialogBaseProps {
118
+ attachments?: "single";
119
+ onSubmit: (data: FeedbackSubmission) => void | Promise<void>;
120
+ onAttachmentError?: (kind: "type" | "size") => void;
121
+ /** Multiple mode only — refused here rather than silently ignored. */
122
+ maxAttachments?: never;
123
+ }
124
+ /**
125
+ * One screenshot plus up to `maxAttachments` picked or pasted files (0.15.5, keksdose
126
+ * dev#578: "pasted two photos, the second overwrote the first"). The capture button is
127
+ * offered while there is no screenshot yet; the add button while there is room.
128
+ */
129
+ interface FeedbackDialogMultipleProps extends FeedbackDialogBaseProps {
130
+ attachments: "multiple";
131
+ /** Default `DEFAULT_MAX_ATTACHMENTS` (5). The screenshot does not count. */
132
+ maxAttachments?: number;
133
+ onSubmit: (data: FeedbackMultipleSubmission) => void | Promise<void>;
134
+ /** `"count"`: more files arrived at once than there was room for; the surplus was dropped. */
135
+ onAttachmentError?: (kind: FeedbackAttachmentError) => void;
136
+ }
137
+ type FeedbackDialogProps = FeedbackDialogSingleProps | FeedbackDialogMultipleProps;
138
+ /**
139
+ * The generic feedback form dialog: category + subject + body + an optional image
140
+ * attachment, with Ctrl/Cmd+Enter to submit. Domain-free — the app supplies the
141
+ * category options, labels and an `onSubmit` that talks to its own backend, plus
142
+ * an optional `contextSlot` for app-specific context (user, current URL, …).
143
+ *
144
+ * **A screenshot can be pasted straight in.** Ctrl/Cmd+V anywhere in the dialog
145
+ * takes an image off the clipboard and makes it the attachment, through the same
146
+ * validation and the same preview as the file picker. It is the gesture the two
147
+ * ways in did not cover: `onCaptureScreenshot` snapshots the *whole* app view,
148
+ * and the file picker needs a file — so somebody who wanted to show one panel,
149
+ * or one region of one, had to save a crop to disk first and then find it again
150
+ * (Steering Design feedback #39). The clipboard is where a region snip already
151
+ * is on every platform.
152
+ *
153
+ * **`attachments="multiple"`** (0.15.5) takes several: every paste and pick adds a
154
+ * chip, and `onSubmit` gets `{ screenshot, attachments }` ({@link
155
+ * FeedbackMultipleSubmission}) instead of `attachment`. Opt-in, so a caller typed
156
+ * against the one-file submission keeps compiling and behaving as before.
157
+ */
158
+ declare function FeedbackDialog(props: FeedbackDialogProps): react.JSX.Element | null;
159
+
160
+ declare const DEFAULT_ATTACHMENT_ACCEPT: string[];
161
+ declare const DEFAULT_MAX_ATTACHMENT_BYTES: number;
162
+ /** How many files `<FeedbackAttachmentField multiple>` takes when `max` is not given
163
+ * (0.15.5). Five photos of one problem is already a lot to look through; a report
164
+ * that needs more is a conversation, which the thread is for. */
165
+ declare const DEFAULT_MAX_ATTACHMENTS = 5;
166
+ /**
167
+ * The field's own strings — the `feedbackAttachment` namespace of `<UiKitProvider
168
+ * labels>`. The keys are {@link FeedbackAttachmentLabels}' own, so the `labels` prop
169
+ * (and a whole `FeedbackDialogLabels` handed down by the dialog) merges over them
170
+ * one to one. The optional heading, `attachment`, stays a prop: a note editor puts
171
+ * the buttons straight under its textarea and wants none.
172
+ *
173
+ * Before 0.7.0 the two optional keys fell back to hard-coded English, so a German app
174
+ * that relied on its provider got "Capture screenshot" under a German form.
175
+ *
176
+ * The three keys added in 0.15.5 for `multiple` mode are optional, so a complete
177
+ * `UiKitLabels` typed before it still compiles; they fall back to English.
178
+ */
179
+ interface FeedbackAttachmentFieldLabels {
180
+ attachmentAdd: string;
181
+ attachmentCapture: string;
182
+ attachmentPaste: string;
183
+ attachmentRemove: string;
184
+ /** `multiple` mode: the accessible name of the list of chosen files. */
185
+ attachmentList?: string;
186
+ /** `multiple` mode: one chip's remove button — "Remove photo.jpg". Named per file,
187
+ * because five buttons all called "Remove attachment" say nothing about which. */
188
+ attachmentRemoveFile?: (name: string) => string;
189
+ /** `multiple` mode: the line shown in place of the add buttons once `max` is reached. */
190
+ attachmentLimit?: (max: number) => string;
191
+ }
192
+ declare const DEFAULT_FEEDBACK_ATTACHMENT_LABELS: FeedbackAttachmentFieldLabels;
193
+ /** Why a file was turned away. `"count"` only ever comes from `multiple` mode: more
194
+ * files arrived at once than `max` left room for, and the surplus was dropped. */
195
+ type FeedbackAttachmentError = "type" | "size" | "count";
196
+ interface FeedbackAttachmentFieldBaseProps {
197
+ /** Prop > `<UiKitProvider labels={{ feedbackAttachment }}>` > English. Optional
198
+ * since 0.7.0; `attachment` (the heading) is only ever read from here. */
199
+ labels?: Partial<FeedbackAttachmentLabels>;
200
+ accept?: string[];
201
+ maxBytes?: number;
202
+ /** Snapshot the app view behind this and return it as a File. A "Capture
203
+ * screenshot" button appears only when it is given. */
204
+ onCaptureScreenshot?: () => Promise<File | null>;
205
+ /** Listen for the paste on `document` rather than on this field's own
206
+ * subtree. For a modal, which owns the whole page while it is up. */
207
+ documentPaste?: boolean;
208
+ /** Listen for the paste within this element's subtree rather than this
209
+ * field's own — for a field standing *beside* the text box a paste is made
210
+ * in, whose common parent is where the event bubbles to. Ignored when
211
+ * `documentPaste` is set. */
212
+ pasteFrom?: RefObject<HTMLElement | null>;
213
+ className?: string;
214
+ }
215
+ /** One file: choosing a second means removing the first. The field's only mode until 0.15.5. */
216
+ interface FeedbackAttachmentFieldSingleProps extends FeedbackAttachmentFieldBaseProps {
217
+ multiple?: false;
218
+ value: File | null;
219
+ onChange: (file: File | null) => void;
220
+ onError?: (kind: "type" | "size") => void;
221
+ max?: never;
222
+ screenshot?: never;
223
+ onScreenshotChange?: never;
224
+ }
225
+ /**
226
+ * Several files (0.15.5, keksdose dev#578: "pasted two photos, the second overwrote
227
+ * the first"). Every way in ADDS — a pick of several files, a paste, a capture — up to
228
+ * `max`, and each file is a removable chip.
229
+ */
230
+ interface FeedbackAttachmentFieldMultipleProps extends FeedbackAttachmentFieldBaseProps {
231
+ multiple: true;
232
+ value: File[];
233
+ onChange: (files: File[]) => void;
234
+ /** How many files `value` may hold. Default {@link DEFAULT_MAX_ATTACHMENTS} (5). The
235
+ * add buttons and the paste hint are offered only while there is room. */
236
+ max?: number;
237
+ /** Per file: a rejected one is reported and the others are still added. */
238
+ onError?: (kind: FeedbackAttachmentError) => void;
239
+ /**
240
+ * A separate slot for THE screenshot, outside `value` and `max`. Given
241
+ * `onScreenshotChange`, what `onCaptureScreenshot` returns lands here instead of in
242
+ * `value`, shown as the first chip, and the capture button is offered only while the
243
+ * slot is empty — a second snapshot of the same view is not more evidence. This is
244
+ * how `<FeedbackDialog attachments="multiple">` keeps the screenshot apart from the
245
+ * photos; a form built from the parts can do the same.
246
+ */
247
+ screenshot?: File | null;
248
+ onScreenshotChange?: (file: File | null) => void;
249
+ }
250
+ type FeedbackAttachmentFieldProps = FeedbackAttachmentFieldSingleProps | FeedbackAttachmentFieldMultipleProps;
251
+ /**
252
+ * Picking one picture: the file dialog, a capture of the app view, or a paste.
253
+ * With `multiple`, picking several (see {@link FeedbackAttachmentFieldMultipleProps}).
254
+ *
255
+ * Lifted out of {@link FeedbackDialog} so the *reply* half of the feature can
256
+ * have it too (Steering Design feedback #128). A report is a conversation — it
257
+ * is filed, it is answered, and the reporter sends it back saying that is not
258
+ * what they meant — and the screenshot showing what they mean is taken at
259
+ * whichever of those points they looked. Only the first of them had a way to
260
+ * attach one, so everything after it had to be described in words.
261
+ *
262
+ * **Three ways in, and they are three because no one of them covers the others.**
263
+ * The file dialog needs a file on disk; `onCaptureScreenshot` snapshots the
264
+ * *whole* app view; and the clipboard is where a region snip already is on every
265
+ * platform (Steering Design feedback #39). Somebody who wanted to show one panel
266
+ * had to save a crop and then find it again.
267
+ *
268
+ * `documentPaste` and `pasteFrom` decide where the paste is listened for, and
269
+ * it is a real choice rather than a flag with a default. A modal traps focus,
270
+ * so while it is up every paste in the page is meant for it — including one
271
+ * made with nothing in particular focused, which never reaches a React
272
+ * `onPaste` on a child: that is `documentPaste`. An editor **inline on a
273
+ * page** is not that: the page around it has its own fields, so it listens
274
+ * within its own subtree and a paste elsewhere stays where it was aimed. But
275
+ * "its own subtree" has to include the text box the paste is actually made in,
276
+ * and that box is this field's *sibling*, not its child — a paste in it bubbles
277
+ * to their common parent and never through here. `pasteFrom` is that parent
278
+ * (Steering Design feedback #140): the element whose subtree is listened to,
279
+ * handed in by whoever renders both the box and this field side by side.
280
+ */
281
+ declare function FeedbackAttachmentField(props: FeedbackAttachmentFieldProps): react.JSX.Element;
282
+ /** What a pasted image is called once it is an attachment.
283
+ *
284
+ * The extension is read off the mime type rather than assumed to be `.png`:
285
+ * Safari puts TIFF on the clipboard and a file called `pasted.png` that is not
286
+ * a PNG is one the receiving end opens wrong. */
287
+ declare function pastedName(type: string): string;
288
+
289
+ export { DEFAULT_ATTACHMENT_ACCEPT as D, type FeedbackAttachmentError as F, DEFAULT_FEEDBACK_ATTACHMENT_LABELS as a, DEFAULT_FEEDBACK_DIALOG_LABELS as b, DEFAULT_MAX_ATTACHMENTS as c, DEFAULT_MAX_ATTACHMENT_BYTES as d, FeedbackAttachmentField as e, type FeedbackAttachmentFieldLabels as f, type FeedbackAttachmentFieldMultipleProps as g, type FeedbackAttachmentFieldProps as h, type FeedbackAttachmentFieldSingleProps as i, type FeedbackAttachmentLabels as j, type FeedbackCategoryOption as k, FeedbackDialog as l, type FeedbackDialogLabels as m, type FeedbackDialogMultipleProps as n, type FeedbackDialogProps as o, type FeedbackDialogSingleProps as p, type FeedbackDialogTextLabels as q, type FeedbackMultipleSubmission as r, type FeedbackSubmission as s, pastedName as t };
@@ -1,5 +1,4 @@
1
- export { DEFAULT_ATTACHMENT_ACCEPT, DEFAULT_FEEDBACK_ATTACHMENT_LABELS, DEFAULT_MAX_ATTACHMENT_BYTES, FeedbackAttachmentField, FeedbackAttachmentFieldLabels, pastedName } from './feedback/feedback-attachment.js';
2
- export { DEFAULT_FEEDBACK_DIALOG_LABELS, FeedbackAttachmentLabels, FeedbackCategoryOption, FeedbackDialog, FeedbackDialogLabels, FeedbackDialogTextLabels, FeedbackSubmission } from './feedback/feedback-dialog.js';
1
+ export { D as DEFAULT_ATTACHMENT_ACCEPT, a as DEFAULT_FEEDBACK_ATTACHMENT_LABELS, b as DEFAULT_FEEDBACK_DIALOG_LABELS, c as DEFAULT_MAX_ATTACHMENTS, d as DEFAULT_MAX_ATTACHMENT_BYTES, F as FeedbackAttachmentError, e as FeedbackAttachmentField, f as FeedbackAttachmentFieldLabels, g as FeedbackAttachmentFieldMultipleProps, h as FeedbackAttachmentFieldProps, i as FeedbackAttachmentFieldSingleProps, j as FeedbackAttachmentLabels, k as FeedbackCategoryOption, l as FeedbackDialog, m as FeedbackDialogLabels, n as FeedbackDialogMultipleProps, o as FeedbackDialogProps, p as FeedbackDialogSingleProps, q as FeedbackDialogTextLabels, r as FeedbackMultipleSubmission, s as FeedbackSubmission, t as pastedName } from './feedback-attachment-BYAHJMOr.js';
3
2
  export { FEEDBACK_CATEGORY_META, FEEDBACK_CATEGORY_ORDER, FEEDBACK_STATUS_META, FEEDBACK_STATUS_ORDER, FeedbackCategory, FeedbackCategoryBadge, FeedbackDetail, FeedbackDetailSection, FeedbackNoteAttachment, FeedbackNoteEditor, FeedbackProse, FeedbackStatus, FeedbackStatusBadge, FeedbackStatusTransitions, feedbackCategoryRank, nextFeedbackStatus, selectableFeedbackStatuses, visibleFeedbackStatuses } from './feedback/feedback-inbox.js';
4
3
  export { DEFAULT_FEEDBACK_COMPOSER_LABELS, DEFAULT_FEEDBACK_THREAD_LABELS, FeedbackComposer, FeedbackComposerAttachment, FeedbackComposerHandle, FeedbackComposerLabels, FeedbackComposerProps, FeedbackThread, FeedbackThreadAttachment, FeedbackThreadEvent, FeedbackThreadItem, FeedbackThreadLabels, FeedbackThreadMessage, FeedbackThreadProps } from './feedback/feedback-thread.js';
5
4
  import 'react';
@@ -1,5 +1,5 @@
1
1
  import { DragEvent, ReactElement } from 'react';
2
- import { aZ as UseFilePickerOptions } from '../kit-labels-CnnBd-2N.js';
2
+ import { aZ as UseFilePickerOptions } from '../kit-labels-BD2F7sOz.js';
3
3
  import '../components/data-table-labels.js';
4
4
  import '../components/mini-calendar.js';
5
5
  import '../components/calendar-heatmap.js';
@@ -31,8 +31,7 @@ import '../components/dialog-frame.js';
31
31
  import '../components/modal.js';
32
32
  import './use-search-param-state.js';
33
33
  import '../components/measured-grid.js';
34
- import '../feedback/feedback-attachment.js';
35
- import '../feedback/feedback-dialog.js';
34
+ import '../feedback-attachment-BYAHJMOr.js';
36
35
  import '../feedback/feedback-thread.js';
37
36
  import '../feedback/feedback-inbox.js';
38
37
  import '../components/account-settings-labels.js';