@reactwright/template-letter 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Reactwright contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # @reactwright/template-letter
2
+
3
+ Formal business-letter template for the Reactwright document engine.
4
+ Single page (typically), US Letter, Times 11pt block-style body.
5
+ Composes the conventional regions of a formal letter via section
6
+ roles: letterhead, date, addressee, subject, salutation, body,
7
+ closing, signature.
8
+
9
+ ## When to use this over alternatives
10
+
11
+ - Pick `@reactwright/template-letter` for cover letters, formal
12
+ business correspondence, legal-style letters, or anything that
13
+ wants the conventional letterhead-date-addressee-body-closing
14
+ shape on a single page.
15
+ - For anything multi-page with sections, headings, and figures, use
16
+ `@reactwright/template-essay`, `@reactwright/template-report`, or
17
+ one of the IEEE variants.
18
+
19
+ ## Format conventions
20
+
21
+ - US Letter, 1" margins all sides.
22
+ - Body: Times New Roman 11pt, line-height 1.3, single-spaced.
23
+ - Letterhead (`role="letterhead"`): sender's name as 14pt bold left-
24
+ aligned heading; address + contact info as 10pt left-aligned
25
+ paragraphs below.
26
+ - Date (`role="date"`): right-aligned 11pt below the letterhead.
27
+ - Addressee (`role="addressee"`): left-aligned 11pt block; name,
28
+ title, organization, address as separate paragraphs.
29
+ - Subject (`role="subject"`): optional bold 11pt "Re: …" line.
30
+ - Salutation (`role="salutation"`): "Dear …,"
31
+ - Body: any paragraphs *not* inside one of the named regions get
32
+ block-style body typography — no indent, 12pt top margin between
33
+ paragraphs.
34
+ - Closing (`role="closing"`): "Sincerely,"
35
+ - Signature (`role="signature"`): name + title + organization, with
36
+ 48pt top margin to leave room for a handwritten signature.
37
+
38
+ No page numbers and no running header.
39
+
40
+ ## Usage
41
+
42
+ ```tsx
43
+ import "reactwright/jsx";
44
+ import { Template } from "@reactwright/template-letter";
45
+
46
+ export { Template };
47
+
48
+ export default function MyLetter() {
49
+ return (
50
+ <document title="Letter to …" author="Sender">
51
+ <section role="letterhead" title="Alex Marsh">
52
+ <p>142 Pine Street</p>
53
+ <p>Carrick, NY 10001</p>
54
+ <p>alex@example.com · (212) 555-0142</p>
55
+ </section>
56
+
57
+ <section role="date" title="">
58
+ <p>1 October 2026</p>
59
+ </section>
60
+
61
+ <section role="addressee" title="">
62
+ <p>Dr. R. Quinlan</p>
63
+ <p>Department of Computer Science</p>
64
+ <p>State University</p>
65
+ <p>Albany, NY 12222</p>
66
+ </section>
67
+
68
+ <section role="subject" title="">
69
+ <p>Re: Submission for Q3 review</p>
70
+ </section>
71
+
72
+ <section role="salutation" title="">
73
+ <p>Dear Dr. Quinlan,</p>
74
+ </section>
75
+
76
+ <p>First body paragraph.</p>
77
+ <p>Second body paragraph.</p>
78
+
79
+ <section role="closing" title="">
80
+ <p>Sincerely,</p>
81
+ </section>
82
+
83
+ <section role="signature" title="">
84
+ <p>Alex Marsh</p>
85
+ <p>Independent Researcher</p>
86
+ </section>
87
+ </document>
88
+ );
89
+ }
90
+ ```
91
+
92
+ ## Implementation notes
93
+
94
+ Each named region is a `<section role="…">`. The template's rules use
95
+ the `within: { kind: "section", role: "<name>" }` selector to scope
96
+ typography. Body paragraphs are anything *not* inside one of the
97
+ named-role sections, so the author can intersperse plain `<p>` blocks
98
+ between the salutation and the closing without needing to wrap them
99
+ in a body region.
100
+
101
+ Use `title=""` on each region to suppress the section-heading; the
102
+ template does not emit one.
103
+
104
+ Styling is expressed entirely via the styling dialect (`<styles>` +
105
+ `<rule>`). The exported `LETTER_CSS` is an empty string.
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@reactwright/template-letter",
3
+ "version": "0.1.0",
4
+ "description": "Formal business letter template for the Reactwright document engine.",
5
+ "license": "MIT",
6
+ "author": "Reactwright contributors",
7
+ "homepage": "https://github.com/PurpleReverie/reactwright/tree/main/packages/template-letter#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/PurpleReverie/reactwright.git",
11
+ "directory": "packages/template-letter"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/PurpleReverie/reactwright/issues"
15
+ },
16
+ "keywords": ["reactwright", "template", "letter", "correspondence", "business"],
17
+ "type": "module",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./src/index.ts",
21
+ "default": "./src/index.ts"
22
+ }
23
+ },
24
+ "files": [
25
+ "src",
26
+ "LICENSE",
27
+ "README.md"
28
+ ],
29
+ "scripts": {
30
+ "check": "tsc --noEmit"
31
+ },
32
+ "peerDependencies": {
33
+ "reactwright": "workspace:*",
34
+ "react": "^18 || ^19"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^22.15.18",
38
+ "@types/react": "^19.1.2",
39
+ "react": "^19.1.0",
40
+ "reactwright": "workspace:*",
41
+ "typescript": "^5.8.3"
42
+ }
43
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ // Formal business-letter helper package. Bundles a Template that
2
+ // styles the conventional regions of a formal letter (letterhead,
3
+ // date, addressee, subject, salutation, body, closing, signature)
4
+ // via section-role rules. Authors tag each region with `role` and
5
+ // the template's rules pick it up — no need for engine-specific
6
+ // markup.
7
+ export { Template, LETTER_STYLES, LETTER_CSS } from "./template.js";
@@ -0,0 +1,243 @@
1
+ import "reactwright/jsx";
2
+
3
+ // Formal business-letter template. One page, US Letter, 1" margins,
4
+ // Times 11pt block-style body (no indent, paragraph spacing). The
5
+ // letter is composed of named regions, each tagged with `role`:
6
+ //
7
+ // role="letterhead" — sender's name + address + contact info, top
8
+ // of page, left-aligned modern style.
9
+ // role="date" — right-aligned date line below letterhead.
10
+ // role="addressee" — left-aligned recipient block (name, title,
11
+ // organization, address).
12
+ // role="subject" — optional bold "Re: …" line.
13
+ // role="salutation" — "Dear …,"
14
+ // role="body" — one or more paragraphs of body prose. NOT
15
+ // a section role; just normal author-side
16
+ // sections without a role get treated as body.
17
+ // role="closing" — "Sincerely,"
18
+ // role="signature" — name + title + organization. The template
19
+ // adds three blank lines above for the
20
+ // handwritten signature.
21
+ //
22
+ // No page numbers, no running headers. Single-page assumed; the
23
+ // engine will paginate if the body overflows.
24
+ //
25
+ // Slice-1+ dialect only. customCss is empty.
26
+
27
+ export const LETTER_STYLES = `
28
+ .letter-letterhead {
29
+ margin: 0 0 24pt 0;
30
+ }
31
+
32
+ .letter-letterhead-heading {
33
+ font-size: 14pt;
34
+ font-weight: bold;
35
+ font-family: 'Times New Roman', Times, serif;
36
+ text-align: left;
37
+ margin: 0 0 2pt 0;
38
+ text-indent: 0;
39
+ break: after(avoid);
40
+ }
41
+
42
+ .letter-letterhead-p {
43
+ font-size: 10pt;
44
+ margin: 0;
45
+ text-indent: 0;
46
+ text-align: left;
47
+ line-height: 1.3;
48
+ }
49
+
50
+ .letter-date {
51
+ margin: 0 0 18pt 0;
52
+ }
53
+
54
+ .letter-date-p {
55
+ margin: 0;
56
+ text-indent: 0;
57
+ text-align: right;
58
+ font-size: 11pt;
59
+ }
60
+
61
+ .letter-addressee {
62
+ margin: 0 0 18pt 0;
63
+ }
64
+
65
+ .letter-addressee-p {
66
+ margin: 0;
67
+ text-indent: 0;
68
+ text-align: left;
69
+ font-size: 11pt;
70
+ line-height: 1.3;
71
+ }
72
+
73
+ .letter-subject {
74
+ margin: 0 0 12pt 0;
75
+ }
76
+
77
+ .letter-subject-p {
78
+ margin: 0;
79
+ text-indent: 0;
80
+ text-align: left;
81
+ font-size: 11pt;
82
+ font-weight: bold;
83
+ }
84
+
85
+ .letter-salutation {
86
+ margin: 0 0 12pt 0;
87
+ }
88
+
89
+ .letter-salutation-p {
90
+ margin: 0;
91
+ text-indent: 0;
92
+ text-align: left;
93
+ font-size: 11pt;
94
+ }
95
+
96
+ .letter-body-p {
97
+ margin: 12pt 0 0 0;
98
+ text-indent: 0;
99
+ text-align: left;
100
+ font-size: 11pt;
101
+ }
102
+
103
+ .letter-closing {
104
+ margin: 18pt 0 0 0;
105
+ }
106
+
107
+ .letter-closing-p {
108
+ margin: 0;
109
+ text-indent: 0;
110
+ text-align: left;
111
+ font-size: 11pt;
112
+ }
113
+
114
+ .letter-signature {
115
+ margin: 48pt 0 0 0;
116
+ }
117
+
118
+ .letter-signature-p {
119
+ margin: 0;
120
+ text-indent: 0;
121
+ text-align: left;
122
+ font-size: 11pt;
123
+ line-height: 1.3;
124
+ }
125
+
126
+ .letter-code-inline {
127
+ background: none;
128
+ padding: 0;
129
+ border-radius: 0;
130
+ font-family: 'SFMono-Regular', Consolas, Menlo, monospace;
131
+ font-size: 0.92em;
132
+ }
133
+ `;
134
+
135
+ // LETTER_CSS is empty. All styling is expressed via the dialect's
136
+ // <styles> block + <rule> bindings.
137
+ export const LETTER_CSS = "";
138
+
139
+ export function Template() {
140
+ return (
141
+ <page
142
+ page={{
143
+ size: "letter",
144
+ marginTop: "1in",
145
+ marginBottom: "1in",
146
+ marginLeft: "1in",
147
+ marginRight: "1in"
148
+ }}
149
+ typography={{
150
+ fontFamily: "'Times New Roman', Times, serif",
151
+ fontSize: "11pt",
152
+ lineHeight: 1.3,
153
+ textAlign: "left"
154
+ }}
155
+ >
156
+ <styles>{LETTER_STYLES}</styles>
157
+
158
+ <rule match={{ kind: "code" }} className="letter-code-inline" />
159
+
160
+ {/* Letterhead */}
161
+ <rule match={{ kind: "section", role: "letterhead" }} className="letter-letterhead" />
162
+ <rule
163
+ match={{ kind: "section-heading", within: { kind: "section", role: "letterhead" } }}
164
+ className="letter-letterhead-heading"
165
+ />
166
+ <rule
167
+ match={{ kind: "paragraph", within: { kind: "section", role: "letterhead" } }}
168
+ className="letter-letterhead-p"
169
+ />
170
+
171
+ {/* Date */}
172
+ <rule match={{ kind: "section", role: "date" }} className="letter-date" />
173
+ <rule
174
+ match={{ kind: "paragraph", within: { kind: "section", role: "date" } }}
175
+ className="letter-date-p"
176
+ />
177
+
178
+ {/* Addressee */}
179
+ <rule match={{ kind: "section", role: "addressee" }} className="letter-addressee" />
180
+ <rule
181
+ match={{ kind: "paragraph", within: { kind: "section", role: "addressee" } }}
182
+ className="letter-addressee-p"
183
+ />
184
+
185
+ {/* Subject */}
186
+ <rule match={{ kind: "section", role: "subject" }} className="letter-subject" />
187
+ <rule
188
+ match={{ kind: "paragraph", within: { kind: "section", role: "subject" } }}
189
+ className="letter-subject-p"
190
+ />
191
+
192
+ {/* Salutation */}
193
+ <rule match={{ kind: "section", role: "salutation" }} className="letter-salutation" />
194
+ <rule
195
+ match={{ kind: "paragraph", within: { kind: "section", role: "salutation" } }}
196
+ className="letter-salutation-p"
197
+ />
198
+
199
+ {/* Closing */}
200
+ <rule match={{ kind: "section", role: "closing" }} className="letter-closing" />
201
+ <rule
202
+ match={{ kind: "paragraph", within: { kind: "section", role: "closing" } }}
203
+ className="letter-closing-p"
204
+ />
205
+
206
+ {/* Signature block — extra top margin to leave room for a
207
+ handwritten signature. */}
208
+ <rule match={{ kind: "section", role: "signature" }} className="letter-signature" />
209
+ <rule
210
+ match={{ kind: "paragraph", within: { kind: "section", role: "signature" } }}
211
+ className="letter-signature-p"
212
+ />
213
+
214
+ {/* Body paragraphs — any paragraph that isn't in a named region
215
+ gets block-style body typography with paragraph spacing. */}
216
+ <rule
217
+ match={{
218
+ kind: "paragraph",
219
+ not: {
220
+ or: [
221
+ { within: { kind: "section", role: "letterhead" } },
222
+ { within: { kind: "section", role: "date" } },
223
+ { within: { kind: "section", role: "addressee" } },
224
+ { within: { kind: "section", role: "subject" } },
225
+ { within: { kind: "section", role: "salutation" } },
226
+ { within: { kind: "section", role: "closing" } },
227
+ { within: { kind: "section", role: "signature" } }
228
+ ]
229
+ }
230
+ }}
231
+ className="letter-body-p"
232
+ />
233
+
234
+ <stack gap="0">
235
+ <region>
236
+ <slot name="title" />
237
+ <slot name="author" />
238
+ <slot name="body" />
239
+ </region>
240
+ </stack>
241
+ </page>
242
+ );
243
+ }