@atom63/resume 0.2.0 → 0.2.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@atom63/resume`. Versions are `0.x` — the API may shift before `1.0`.
4
+
5
+ ## 0.2.2
6
+
7
+ - **Fix: final oversized blocks no longer create a trailing blank page.**
8
+ - **Fix: custom MDX components now merge over the defaults.** Consumers can pass
9
+ `components={{ SkillBar }}` without spreading the built-in resume components.
10
+ - **Fix: dev write-back always restores the file watcher** and returns JSON for
11
+ write failures instead of leaving the watcher unregistered.
12
+
13
+ ## 0.2.1
14
+
15
+ Standalone-rendering fixes. If you saw oversized, off-center pages or loose
16
+ spacing in a non-OS63 app, this release corrects it. **The fixes change how the
17
+ document renders — re-check your layout after upgrading.**
18
+
19
+ - **Fix: pages rendered too wide / off-center.** The page frames assumed a global
20
+ `box-sizing: border-box` reset; the package now ships its own (scoped to the
21
+ document), so pages are the correct paper size and stay centered.
22
+ - **Fix: loose vertical spacing.** User-agent margins on headings/paragraphs/lists
23
+ were adding to the layout's flex gaps. The package now resets them (scoped).
24
+ - **Fix: token overrides could be ignored.** Components self-imported the CSS,
25
+ re-injecting it after a consumer's overrides. Styles now ship only via the
26
+ `@atom63/resume/styles` entry — **import it once in your app** — so your
27
+ `--doc-*` overrides reliably win.
28
+ - **Fix: phantom horizontal scrollbar.** The hidden measuring layer was pushed
29
+ far off-screen, inflating the scroll area; it's now clipped to 0×0.
30
+ - **Font follows the host app** by default (`font-family: var(--doc-font, inherit)`)
31
+ instead of the browser default. Set `--doc-font` to choose a specific stack; the
32
+ `create-resume` scaffold sets a clean sans stack in its `index.css`.
33
+ - Viewer chrome polish (primary Save-to-PDF, segmented zoom controls).
34
+
35
+ ## 0.2.0
36
+
37
+ - **`pageSize` prop** (`'letter' | 'a4'`, default `'letter'`) on `ResumeViewer`
38
+ and via `ResumePageSizeContext`. Drives pagination, the on-screen page, and the
39
+ `@page` print size. New exports: `getPageGeometry`, `PageSize`, `PageGeometry`.
40
+ - Removed the unwired `--paper-*` tokens (page size is the prop now; `--doc-*`
41
+ remains the styling vocabulary).
42
+
43
+ ## 0.1.0
44
+
45
+ - Initial release: paginated MDX resume/CV engine, `ResumeViewer`, the MDX
46
+ primitives, `packIntoPages`, the `--doc-*` token system, and the optional
47
+ `./editor` and `./vite` subexports.
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # @atom63/resume
2
+
3
+ **Write your resume and CV as MDX — paginated, print-ready, in React.**
4
+
5
+ A resume is just an `.mdx` file built from a small grammar of composable
6
+ primitives. The engine paginates it into real 8.5×11″ (or A4) pages, renders a
7
+ zoom/pan viewer, and prints to a clean multi-page PDF. Because the document is
8
+ *code*, a coding agent can write it from your notes — and you keep the MDX as the
9
+ source of truth.
10
+
11
+ ![The ResumeViewer rendering a resume](https://raw.githubusercontent.com/atom63/resume/main/packages/resume/media/demo.png)
12
+
13
+ > Status: `0.2.x`. The API may shift before `1.0`. See [CHANGELOG](./CHANGELOG.md).
14
+
15
+ ## Two ways to use it
16
+
17
+ ### 1. Scaffold a project
18
+
19
+ ```bash
20
+ npm create @atom63/resume@latest my-resume
21
+ cd my-resume && npm install && npm run dev
22
+ ```
23
+
24
+ You get a standalone Vite app with starter `src/resume.mdx` (two-column) and
25
+ `src/cv.mdx` (single-column). Point a coding agent at those files to write the
26
+ content; Save to PDF from the viewer toolbar.
27
+
28
+ ### 2. Add the module to a React app
29
+
30
+ ```bash
31
+ npm i @atom63/resume
32
+ ```
33
+
34
+ ```tsx
35
+ import { ResumeViewer } from '@atom63/resume'
36
+ import '@atom63/resume/styles' // import the styles ONCE in your app
37
+ import Resume from './resume.mdx'
38
+
39
+ export default () => <ResumeViewer Content={Resume} pdfFilename="Resume" pageSize="letter" />
40
+ ```
41
+
42
+ Your app needs the MDX + raw-import Vite wiring shown in the scaffolded
43
+ `vite.config.ts` (`@mdx-js/rollup` + `mdxRawPlugin` from `@atom63/resume/vite`).
44
+
45
+ ## Exports
46
+
47
+ | Export | What it is |
48
+ |---|---|
49
+ | `@atom63/resume` | `ResumeViewer`, the `PaginatedResume` engine + MDX primitives, `packIntoPages`, `useResumeViewport`, `getPageGeometry` |
50
+ | `@atom63/resume/editor` | `ResumeEditor` + `MdxLivePreview` — optional in-app live MDX editor |
51
+ | `@atom63/resume/vite` | `mdxRawPlugin` (so `import src from './resume.mdx?raw'` works) + `resumeWriteBackPlugin` |
52
+ | `@atom63/resume/styles` | import-and-done stylesheet (tokens + document + viewer chrome) |
53
+ | `@atom63/resume/tokens` | just the `--doc-*` design tokens |
54
+
55
+ ## The MDX grammar
56
+
57
+ ```mdx
58
+ <ResumeDocument>
59
+ <Header>
60
+ <HeaderLeft># Jane Doe</HeaderLeft>
61
+ <HeaderRight>Senior Product Engineer</HeaderRight>
62
+ </Header>
63
+ <Columns>
64
+ <Sidebar>
65
+ ### Skills
66
+ - TypeScript, React
67
+ </Sidebar>
68
+ <Main>
69
+ ### Experience
70
+ <Group>
71
+ #### Engineer @ Acme
72
+ _2022 – Present_
73
+ - Built things.
74
+ </Group>
75
+ </Main>
76
+ </Columns>
77
+ <Footer>jane@example.com</Footer>
78
+ </ResumeDocument>
79
+ ```
80
+
81
+ Single-column CVs put everything in `<Main>` and use `<Section label="…">` +
82
+ `<Entry year role>` record rows.
83
+
84
+ ## Restyle (modify)
85
+
86
+ The look is a **Tailwind-free** token system. Override any token, scoped to
87
+ `[data-resume-document]` (in your app's CSS, loaded after `@atom63/resume/styles`):
88
+
89
+ ```css
90
+ [data-resume-document] {
91
+ --doc-text: 11px; /* body size */
92
+ --doc-ink: #111; /* headings + bold */
93
+ --doc-ink-body: #404040; /* body copy */
94
+ --doc-resume-cols: 1fr 2fr; /* sidebar : main ratio */
95
+ --doc-font: 'Charter', Georgia, serif; /* or `inherit` to follow the host font */
96
+ }
97
+ ```
98
+
99
+ - **Paper size** is the `pageSize` prop (`'letter' | 'a4'`), not a token — it drives
100
+ pagination, the on-screen page, and the PDF.
101
+
102
+ ## Extend
103
+
104
+ Add your own section types by passing a custom MDX component map to
105
+ `ResumeViewer` (it merges over the defaults):
106
+
107
+ ```tsx
108
+ import { ResumeViewer, resumeMdxComponents } from '@atom63/resume'
109
+
110
+ function SkillBar({ label, level }: { label: string; level: number }) {
111
+ return (
112
+ <div className="doc-meta-grid">
113
+ <span className="doc-meta">{label}</span>
114
+ <div style={{ background: '#eee', height: 4 }}>
115
+ <div style={{ width: `${level}%`, height: 4, background: '#111' }} />
116
+ </div>
117
+ </div>
118
+ )
119
+ }
120
+
121
+ <ResumeViewer
122
+ Content={Resume}
123
+ components={{ ...resumeMdxComponents, SkillBar }}
124
+ />
125
+ ```
126
+
127
+ Then use `<SkillBar label="React" level={90} />` in your MDX. The `.doc-*` classes
128
+ (`doc-meta-grid`, `doc-meta`, `doc-body`, `doc-heading`, …) compose with the token
129
+ system, so custom components stay on-brand. Each top-level child of a `<Sidebar>`
130
+ / `<Main>` is one pagination block, so pages can break between them.
131
+
132
+ ## Limitations
133
+
134
+ - Markdown tables render unstyled (the engine ships no table styling).
135
+
136
+ ## License
137
+
138
+ MIT
@@ -64,7 +64,8 @@ function packColumn(blocks, pageUsableHeight, gap) {
64
64
  pageOf[b.id] = page;
65
65
  used += (used > 0 ? gap : 0) + b.height;
66
66
  }
67
- return { pageOf, pages: page + 1, oversized };
67
+ const pages = blocks.length === 0 ? 1 : page + (used > 0 ? 1 : 0);
68
+ return { pageOf, pages, oversized };
68
69
  }
69
70
  function packIntoPages(input) {
70
71
  const gap = input.blockGap ?? 0;
@@ -312,33 +313,40 @@ function PaginatedResume({ children }) {
312
313
  clearTimeout(settleTimer);
313
314
  };
314
315
  }, [contentKey]);
315
- const measureLayer = /* @__PURE__ */ jsxs(
316
+ const measureLayer = /* @__PURE__ */ jsx(
316
317
  "div",
317
318
  {
318
319
  "aria-hidden": true,
319
- "data-resume-measure": true,
320
- ref: measureRef,
321
320
  style: {
322
321
  position: "absolute",
323
322
  top: 0,
324
- left: -99999,
325
- width: geo.contentWidthPx,
326
- visibility: "hidden",
323
+ left: 0,
324
+ width: 0,
325
+ height: 0,
326
+ overflow: "hidden",
327
327
  pointerEvents: "none"
328
328
  },
329
- children: [
330
- header,
331
- blocks.sidebar.length === 0 ? (
332
- // Single-column docs (e.g. the CV) put everything in Main and render
333
- // full-width. Measure at full width too so block heights match the
334
- // full-width page render below (otherwise they'd be measured at the
335
- // narrower 2/3 main-column width and mis-paginate).
336
- /* @__PURE__ */ jsx("div", { className: "doc-col", "data-resume-col": "main", children: blocks.main })
337
- ) : /* @__PURE__ */ jsxs(Columns, { children: [
338
- /* @__PURE__ */ jsx(Sidebar, { children: blocks.sidebar }),
339
- /* @__PURE__ */ jsx(Main, { children: blocks.main })
340
- ] })
341
- ]
329
+ children: /* @__PURE__ */ jsxs(
330
+ "div",
331
+ {
332
+ "data-resume-measure": true,
333
+ ref: measureRef,
334
+ style: { width: geo.contentWidthPx, visibility: "hidden" },
335
+ children: [
336
+ header,
337
+ blocks.sidebar.length === 0 ? (
338
+ // Single-column docs (e.g. the CV) put everything in Main and render
339
+ // full-width. Measure at full width too so block heights match the
340
+ // full-width page render below (otherwise they'd be measured at the
341
+ // narrower 2/3 main-column width and mis-paginate).
342
+ /* @__PURE__ */ jsx("div", { className: "doc-col", "data-resume-col": "main", children: blocks.main })
343
+ ) : /* @__PURE__ */ jsxs(Columns, { children: [
344
+ /* @__PURE__ */ jsx(Sidebar, { children: blocks.sidebar }),
345
+ /* @__PURE__ */ jsx(Main, { children: blocks.main })
346
+ ] })
347
+ ]
348
+ }
349
+ )
342
350
  }
343
351
  );
344
352
  if (!heights) {
@@ -398,5 +406,5 @@ function PageCountReporter({ count, report }) {
398
406
  }
399
407
 
400
408
  export { BLOCK_GAP_PX, Columns, Entry, Footer, Group, Header, Main, PAGE, PaginatedResume, PaginationReportContext, ResumeFontFamilyContext, ResumePageSizeContext, Rule, Section, Sidebar, WRAPPER_PADDING_X, getPageGeometry, packIntoPages, resumeMdxComponents, usePaginationReport, useResumeFontFamily, useResumePageSize };
401
- //# sourceMappingURL=chunk-ARBKVUHN.js.map
402
- //# sourceMappingURL=chunk-ARBKVUHN.js.map
409
+ //# sourceMappingURL=chunk-V7BVTGX3.js.map
410
+ //# sourceMappingURL=chunk-V7BVTGX3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/geometry.ts","../src/pagination/pagination.ts","../src/document/pagination-context.tsx","../src/mdx/base-components.tsx","../src/mdx/external-href.ts","../src/document/components.tsx","../src/document/paginated-resume.tsx"],"names":["jsx","jsxs","_"],"mappings":"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","file":"chunk-V7BVTGX3.js","sourcesContent":["// packages/resume/src/geometry.ts\n// Numeric page geometry — the single source of truth shared by the JS packer\n// and the rendered page frames. Print-fixed px at 96dpi for PDF fidelity.\n\nconst DPI = 96\nconst MM = DPI / 25.4\n\nexport type PageSize = 'letter' | 'a4'\n\nexport interface PageGeometry {\n widthPx: number\n heightPx: number\n padXPx: number\n padYPx: number\n /** Screen-only gap between page frames. */\n gapPx: number\n contentWidthPx: number\n usableHeightPx: number\n /** Value for the CSS `@page { size: … }` print rule. */\n cssPageSize: 'letter' | 'A4'\n}\n\n// Both sizes keep the same physical 0.7in x 0.6in margins.\nconst PAD_X_PX = 0.7 * DPI\nconst PAD_Y_PX = 0.6 * DPI\nconst GAP_PX = 32\n\nconst DIMENSIONS: Record<\n PageSize,\n { widthPx: number; heightPx: number; cssPageSize: 'letter' | 'A4' }\n> = {\n letter: { widthPx: 8.5 * DPI, heightPx: 11 * DPI, cssPageSize: 'letter' },\n a4: { widthPx: 210 * MM, heightPx: 297 * MM, cssPageSize: 'A4' },\n}\n\n/** Resolve the print-fixed geometry for a page size (defaults to US Letter). */\nexport function getPageGeometry(size: PageSize = 'letter'): PageGeometry {\n const d = DIMENSIONS[size]\n return {\n widthPx: d.widthPx,\n heightPx: d.heightPx,\n padXPx: PAD_X_PX,\n padYPx: PAD_Y_PX,\n gapPx: GAP_PX,\n contentWidthPx: d.widthPx - 2 * PAD_X_PX,\n usableHeightPx: d.heightPx - 2 * PAD_Y_PX,\n cssPageSize: d.cssPageSize,\n }\n}\n\n/** Back-compat default geometry (US Letter). */\nexport const PAGE = getPageGeometry('letter')\n\n// Kept for back-compat; equal to the Letter geometry's derived values.\nexport const CONTENT_WIDTH_PX = PAGE.contentWidthPx\nexport const USABLE_HEIGHT_PX = PAGE.usableHeightPx\n\n// Vertical gap between blocks within a column — must match --doc-block-gap\n// (0.375rem = 6px) in styles/tokens.css and the column gap in document.css.\nexport const BLOCK_GAP_PX = 6\n\n// Outer horizontal padding the viewer reserves around the page in its scroll area.\nexport const WRAPPER_PADDING_X = 32\n","// packages/resume/src/pagination/pagination.ts\n\nexport interface Block {\n id: string\n /** Measured px (offsetHeight + vertical margins). */\n height: number\n /** Section headings: don't leave them orphaned at a page bottom. */\n keepWithNext: boolean\n}\n\nexport type ColumnKey = 'sidebar' | 'main'\n\nexport interface PackInput {\n columns: Record<ColumnKey, Block[]>\n /** Usable content height for a given page index; index 0 may be shorter (header band). */\n pageUsableHeight: (pageIndex: number) => number\n /**\n * Vertical gap rendered between consecutive blocks in a column (the flex\n * `gap`). Block heights are measured individually, so the packer must add\n * this back or pages overflow once they hold many blocks. Defaults to 0.\n */\n blockGap?: number\n}\n\nexport interface PackResult {\n pageCount: number\n pageOf: Record<ColumnKey, Record<string, number>>\n /** Blocks taller than a full page — placed alone, allowed to overflow. */\n oversized: string[]\n}\n\nfunction packColumn(\n blocks: Block[],\n pageUsableHeight: (p: number) => number,\n gap: number\n): { pageOf: Record<string, number>; pages: number; oversized: string[] } {\n const pageOf: Record<string, number> = {}\n const oversized: string[] = []\n let page = 0\n let used = 0\n\n for (let i = 0; i < blocks.length; i++) {\n const b = blocks[i]\n let cap = pageUsableHeight(page)\n // A gap precedes every block except the first on its page.\n const gapBefore = used > 0 ? gap : 0\n\n // Move to a fresh page if this block (plus its leading gap) overflows.\n if (used > 0 && used + gapBefore + b.height > cap) {\n page++\n used = 0\n cap = pageUsableHeight(page)\n } else if (\n // Keep-with-next: heading fits alone but heading + gap + next block\n // doesn't — push the heading forward so it isn't orphaned.\n used > 0 &&\n b.keepWithNext &&\n used + gapBefore + b.height <= cap &&\n i + 1 < blocks.length &&\n used + gapBefore + b.height + gap + blocks[i + 1].height > cap\n ) {\n page++\n used = 0\n cap = pageUsableHeight(page)\n }\n\n // Oversized: taller than a whole (now-empty) page. Place alone, allow overflow.\n if (b.height > cap && used === 0) {\n oversized.push(b.id)\n pageOf[b.id] = page\n page++\n used = 0\n continue\n }\n\n pageOf[b.id] = page\n used += (used > 0 ? gap : 0) + b.height\n }\n\n const pages = blocks.length === 0 ? 1 : page + (used > 0 ? 1 : 0)\n return { pageOf, pages, oversized }\n}\n\n/** Assign measured blocks to pages per column. Pure: no DOM. */\nexport function packIntoPages(input: PackInput): PackResult {\n const gap = input.blockGap ?? 0\n const sidebar = packColumn(input.columns.sidebar, input.pageUsableHeight, gap)\n const main = packColumn(input.columns.main, input.pageUsableHeight, gap)\n return {\n pageCount: Math.max(sidebar.pages, main.pages, 1),\n pageOf: { sidebar: sidebar.pageOf, main: main.pageOf },\n oversized: [...sidebar.oversized, ...main.oversized],\n }\n}\n","// packages/resume/src/document/pagination-context.tsx\nimport { createContext, useContext } from 'react'\nimport type { PageSize } from '../geometry'\n\n/** PaginatedResume reports its computed page count up to the host (ResumeViewer). */\nexport const PaginationReportContext = createContext<((pageCount: number) => void) | null>(null)\n\nexport function usePaginationReport(): (pageCount: number) => void {\n const report = useContext(PaginationReportContext)\n return report ?? (() => {})\n}\n\n/** Optional font-family hint — changes trigger re-measure/re-pagination. */\nexport const ResumeFontFamilyContext = createContext<string | undefined>(undefined)\nexport const useResumeFontFamily = () => useContext(ResumeFontFamilyContext)\n\n/** Page size for the document — a change re-measures/re-paginates. */\nexport const ResumePageSizeContext = createContext<PageSize>('letter')\nexport const useResumePageSize = () => useContext(ResumePageSizeContext)\n","import type React from 'react'\n\n/**\n * Vendored, dependency-free base prose component map.\n *\n * This is a minimal fallback map that the resume spreads over\n * (`...baseMdxComponents`) before defining its own `h1/h3/h4/p/ul/li/strong/em/a/hr`.\n * It deliberately has NO dependency on `@atom63/ui`, lightbox, article blocks,\n * example containers, or any other `@atom63/*` package — every entry is a plain\n * HTML-element component so the resume package stays self-contained.\n *\n * It only needs to provide sane defaults for elements the resume does NOT override.\n */\nexport const baseMdxComponents = {\n h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => <h2 {...props} />,\n h5: (props: React.HTMLAttributes<HTMLHeadingElement>) => <h5 {...props} />,\n h6: (props: React.HTMLAttributes<HTMLHeadingElement>) => <h6 {...props} />,\n ol: (props: React.HTMLAttributes<HTMLOListElement>) => <ol {...props} />,\n blockquote: (props: React.HTMLAttributes<HTMLElement>) => <blockquote {...props} />,\n code: (props: React.HTMLAttributes<HTMLElement>) => <code {...props} />,\n pre: (props: React.HTMLAttributes<HTMLPreElement>) => <pre {...props} />,\n img: (props: React.ImgHTMLAttributes<HTMLImageElement>) => (\n // biome-ignore lint/a11y/useAltText: alt is forwarded via spread props\n <img {...props} />\n ),\n} as const\n","const MDX_SPECIAL_PROTOCOL = /^(mailto|tel|javascript):/i\n\n/**\n * True when `href` should open in a new tab: off-origin http(s), protocol-relative,\n * or absolute http(s) during SSR. Same-origin URLs, in-app paths (`/…`, `#…`),\n * relative paths, and `mailto:` / `tel:` / `javascript:` stay in-tab / default behavior.\n */\nexport function isExternalMdxHref(href: string | undefined): boolean {\n if (!href) {\n return false\n }\n const t = href.trim()\n if (t.startsWith('#') || t.startsWith('/')) {\n return false\n }\n if (MDX_SPECIAL_PROTOCOL.test(t)) {\n return false\n }\n if (t.startsWith('//')) {\n return true\n }\n if (typeof globalThis.window !== 'undefined') {\n try {\n const u = new URL(t, globalThis.window.location.href)\n if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n return false\n }\n return u.origin !== globalThis.window.location.origin\n } catch {\n return false\n }\n }\n try {\n const u = new URL(t)\n return u.protocol === 'http:' || u.protocol === 'https:'\n } catch {\n return false\n }\n}\n","import clsx from 'clsx'\nimport { baseMdxComponents } from '../mdx/base-components'\nimport { isExternalMdxHref } from '../mdx/external-href'\nimport { PaginatedResume } from './paginated-resume'\n\n// Styling for these primitives lives in resume-document.css as a small token\n// system (--doc-*) + semantic classes (.doc-*). Components only compose those —\n// no hardcoded sizes/colors/grid widths — so the resume and CV share one source\n// of truth. See paginated-resume.tsx for where the .css is imported and where\n// the [data-resume-document] token scope is applied.\n\nexport function Header({\n children,\n meta = false,\n}: {\n children: React.ReactNode\n /**\n * Use the universal meta grid (left label column + content), the same track\n * widths as <Section> and <Entry>, so the header aligns with everything\n * below it. The default is the resume's sidebar|main split.\n */\n meta?: boolean\n}) {\n return (\n <div\n className={clsx('doc-header', meta ? 'doc-meta-grid' : 'doc-resume-grid')}\n data-resume-header\n >\n {children}\n </div>\n )\n}\n\nfunction HeaderLeft({ children }: { children: React.ReactNode }) {\n return <div className=\"doc-header-col doc-header-left\">{children}</div>\n}\n\nfunction HeaderRight({ children }: { children: React.ReactNode }) {\n return <div className=\"doc-header-col doc-header-right\">{children}</div>\n}\n\nfunction Links({ children }: { children: React.ReactNode }) {\n return <div className=\"doc-group doc-links\">{children}</div>\n}\n\nexport function Group({ children }: { children: React.ReactNode }) {\n return <div className=\"doc-group\">{children}</div>\n}\n\n/**\n * A record row (award, media mention, talk, …): a `year | role` meta column on\n * the left and the linked title on the right. Each Entry is a single pagination\n * block, so render long CV lists as a flat sequence of Entry elements (NOT one\n * <ul>) so pages can break between them.\n */\nexport function Entry({\n year,\n role,\n children,\n}: {\n year?: string\n role?: string\n children: React.ReactNode\n}) {\n return (\n <div className=\"doc-meta-grid\">\n <span className=\"doc-meta\">{role ? `${year} | ${role}` : year}</span>\n <div className=\"doc-body doc-entry-body\">{children}</div>\n </div>\n )\n}\n\n/** A thin full-width divider — the CV uses one under the header band. */\nexport function Rule() {\n return <div className=\"doc-rule\" />\n}\n\n/**\n * Editorial section: the label sits in the left meta column (aligned with the\n * `year | role` column of Entry rows) and the content fills the right column,\n * so prose sections share one left edge with the record rows below. The\n * .doc-section margin keeps every section on the same vertical rhythm as the\n * record-section headings (h3). One pagination block — keep a body under a page.\n */\nexport function Section({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"doc-section doc-meta-grid\">\n <h3 className=\"doc-heading\">{label}</h3>\n <div className=\"doc-col\">{children}</div>\n </div>\n )\n}\n\nexport function Footer({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"doc-footer\" data-footer>\n {children}\n </div>\n )\n}\n\nexport function Columns({ children }: { children: React.ReactNode }) {\n return <div className=\"doc-resume-grid\">{children}</div>\n}\n\nexport function Sidebar({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"doc-col doc-col-sidebar\" data-resume-col=\"sidebar\">\n {children}\n </div>\n )\n}\n\nexport function Main({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"doc-col doc-col-main\" data-resume-col=\"main\">\n {children}\n </div>\n )\n}\n\nexport const resumeMdxComponents = {\n ...baseMdxComponents,\n\n ResumeDocument: PaginatedResume,\n\n Header,\n HeaderLeft,\n HeaderRight,\n Links,\n Group,\n Entry,\n Rule,\n Section,\n Footer,\n Columns,\n Sidebar,\n Main,\n\n h1: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n <h1 className=\"doc-title\" {...props}>\n {children}\n </h1>\n ),\n\n h3: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n <h3 className=\"doc-section doc-heading\" data-resume-keep-with-next {...props}>\n {children}\n </h3>\n ),\n\n h4: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n <h4 className=\"doc-subheading\" {...props}>\n {children}\n </h4>\n ),\n\n p: ({ children, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => (\n <p className=\"doc-body\" {...props}>\n {children}\n </p>\n ),\n\n ul: ({ children, ...props }: React.HTMLAttributes<HTMLUListElement>) => (\n <ul className=\"doc-list\" {...props}>\n {children}\n </ul>\n ),\n\n li: ({ children, ...props }: React.HTMLAttributes<HTMLLIElement>) => (\n <li className=\"doc-body\" {...props}>\n {children}\n </li>\n ),\n\n strong: ({ children, ...props }: React.HTMLAttributes<HTMLElement>) => (\n <strong className=\"doc-strong\" {...props}>\n {children}\n </strong>\n ),\n\n em: ({ children, ...props }: React.HTMLAttributes<HTMLElement>) => (\n <em className=\"doc-meta doc-em\" {...props}>\n {children}\n </em>\n ),\n\n a: ({ children, href, target, rel, ...props }: React.AnchorHTMLAttributes<HTMLAnchorElement>) => {\n const external = isExternalMdxHref(href)\n return (\n <a\n className=\"doc-link\"\n href={href}\n {...props}\n rel={external ? (rel ?? 'noopener noreferrer') : rel}\n target={external ? (target ?? '_blank') : target}\n >\n {children}\n </a>\n )\n },\n\n hr: (_props: React.HTMLAttributes<HTMLHRElement>) => <div className=\"doc-hr\" />,\n}\n","import {\n Children,\n Fragment,\n isValidElement,\n type ReactNode,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react'\nimport { BLOCK_GAP_PX, getPageGeometry } from '../geometry'\nimport { type Block, type ColumnKey, packIntoPages } from '../pagination/pagination'\nimport { Columns, Footer, Header, Main, Sidebar } from './components'\nimport { usePaginationReport, useResumeFontFamily, useResumePageSize } from './pagination-context'\n\n// Styles ship via the `@atom63/resume/styles` entry (import it once in your app)\n// — NOT self-imported here, so a consumer's token overrides always win the\n// cascade instead of racing a re-injected copy of the package CSS.\n\ntype Columned = Record<ColumnKey, ReactNode[]>\n\n/**\n * Flatten one level, descending through Fragments. MDX wraps top-level content\n * (and component children) in Fragments, so `Children.toArray` alone yields the\n * Fragment, not the Header/Columns/Sidebar elements inside it.\n */\nfunction flattenChildren(children: ReactNode): ReactNode[] {\n const out: ReactNode[] = []\n for (const child of Children.toArray(children)) {\n if (isValidElement(child) && child.type === Fragment) {\n out.push(...flattenChildren((child.props as { children: ReactNode }).children))\n } else {\n out.push(child)\n }\n }\n return out\n}\n\n/** Pull Header / Columns(Sidebar,Main) / Footer out of the MDX wrapper children. */\nfunction extract(children: ReactNode): {\n header: ReactNode | null\n footer: ReactNode | null\n blocks: Columned\n} {\n let header: ReactNode | null = null\n let footer: ReactNode | null = null\n const blocks: Columned = { sidebar: [], main: [] }\n\n for (const child of flattenChildren(children)) {\n if (!isValidElement(child)) continue\n if (child.type === Header) header = child\n else if (child.type === Footer) footer = child\n else if (child.type === Columns) {\n for (const col of flattenChildren((child.props as { children: ReactNode }).children)) {\n if (!isValidElement(col)) continue\n const key: ColumnKey | null =\n col.type === Sidebar ? 'sidebar' : col.type === Main ? 'main' : null\n if (key) {\n blocks[key] = flattenChildren((col.props as { children: ReactNode }).children)\n }\n }\n }\n }\n return { header, footer, blocks }\n}\n\n/** Read a block element's full vertical extent (border box + margins). */\nfunction blockHeight(el: HTMLElement): number {\n const cs = getComputedStyle(el)\n const mt = Number.parseFloat(cs.marginTop) || 0\n const mb = Number.parseFloat(cs.marginBottom) || 0\n return el.getBoundingClientRect().height + mt + mb\n}\n\n/**\n * Mounted as the MDX `wrapper`, so it receives [Header, Columns, Footer].\n * Measures each column's blocks in a hidden layer, packs them into pages, and\n * renders physical page frames. Reports pageCount up to ResumeApp.\n */\nexport function PaginatedResume({ children }: { children: ReactNode }) {\n const { header, footer, blocks } = extract(children)\n const fontFamily = useResumeFontFamily()\n const pageSize = useResumePageSize()\n const geo = getPageGeometry(pageSize)\n const report = usePaginationReport()\n\n const measureRef = useRef<HTMLDivElement>(null)\n const [heights, setHeights] = useState<Record<ColumnKey, number[]> | null>(null)\n const [headerH, setHeaderH] = useState(0)\n\n // contentKey changes whenever the rendered content could change height.\n // Print-fixed (px) sizes: only the inherited font *family* and the block\n // counts can change measured heights — the OS typography scale is ignored.\n const contentKey = `${fontFamily}:${pageSize}:${blocks.sidebar.length}:${blocks.main.length}`\n\n // contentKey is the intentional re-measure trigger: a change in font family /\n // block counts must force a fresh measure even though it isn't read in the body.\n // biome-ignore lint/correctness/useExhaustiveDependencies: deliberate re-run trigger\n useLayoutEffect(() => {\n const root = measureRef.current\n if (!root) return\n const measure = () => {\n const cols: Record<ColumnKey, number[]> = { sidebar: [], main: [] }\n for (const key of ['sidebar', 'main'] as ColumnKey[]) {\n const colEl = root.querySelector(`[data-resume-col=\"${key}\"]`)\n if (colEl) {\n cols[key] = Array.from(colEl.children).map(c => blockHeight(c as HTMLElement))\n }\n }\n const headerEl = root.querySelector('[data-resume-header]') as HTMLElement | null\n setHeaderH(headerEl ? blockHeight(headerEl) : 0)\n setHeights(cols)\n }\n measure()\n const ro = new ResizeObserver(measure)\n ro.observe(root)\n\n // Re-measure on window (os63 window) resize — e.g. maximize/restore. The\n // measure root is fixed-width, so its own observer never catches this;\n // watch the enclosing scroll viewport, which tracks the window size. A\n // double rAF lets layout settle so a mid-transition read doesn't stick\n // (which collapsed multi-page docs to a single clipped page).\n const viewport = root.closest('[data-slot=\"scroll-area-viewport\"]')\n // Debounce to a TRAILING measure: the os63 window's maximize/restore is a\n // spring animation, so reading mid-transition lands on a wrong height that\n // then sticks. Wait for the resize to stop, then measure the settled layout.\n let settleTimer: ReturnType<typeof setTimeout> | undefined\n const scheduleMeasure = () => {\n clearTimeout(settleTimer)\n settleTimer = setTimeout(measure, 250)\n }\n const vpObserver = viewport ? new ResizeObserver(scheduleMeasure) : null\n vpObserver?.observe(viewport as Element)\n\n if (typeof document !== 'undefined' && 'fonts' in document) {\n document.fonts.ready.then(measure).catch(() => {})\n }\n return () => {\n ro.disconnect()\n vpObserver?.disconnect()\n clearTimeout(settleTimer)\n }\n }, [contentKey])\n\n // The hidden measuring layer renders the real structure at content width.\n // A 0x0 overflow-hidden clip wrapper keeps it out of the scroll area (a large\n // negative offset would inflate the viewport and spawn a phantom horizontal\n // scrollbar, drifting the page off-center). The INNER element keeps its\n // natural size so block heights stay measurable and its ResizeObserver still\n // fires on content changes.\n const measureLayer = (\n <div\n aria-hidden\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: 0,\n height: 0,\n overflow: 'hidden',\n pointerEvents: 'none',\n }}\n >\n <div\n data-resume-measure\n ref={measureRef}\n style={{ width: geo.contentWidthPx, visibility: 'hidden' }}\n >\n {header}\n {blocks.sidebar.length === 0 ? (\n // Single-column docs (e.g. the CV) put everything in Main and render\n // full-width. Measure at full width too so block heights match the\n // full-width page render below (otherwise they'd be measured at the\n // narrower 2/3 main-column width and mis-paginate).\n <div className=\"doc-col\" data-resume-col=\"main\">\n {blocks.main}\n </div>\n ) : (\n <Columns>\n <Sidebar>{blocks.sidebar}</Sidebar>\n <Main>{blocks.main}</Main>\n </Columns>\n )}\n </div>\n </div>\n )\n\n if (!heights) {\n return <div data-resume-document>{measureLayer}</div>\n }\n\n const toBlocks = (key: ColumnKey): Block[] =>\n blocks[key].map((node, i) => ({\n id: `${key}-${i}`,\n height: heights[key][i] ?? 0,\n keepWithNext:\n isValidElement(node) &&\n Boolean((node.props as Record<string, unknown>)['data-resume-keep-with-next']),\n }))\n\n const sidebarBlocks = toBlocks('sidebar')\n const mainBlocks = toBlocks('main')\n\n const pack = packIntoPages({\n columns: { sidebar: sidebarBlocks, main: mainBlocks },\n pageUsableHeight: p =>\n p === 0 ? Math.max(0, geo.usableHeightPx - headerH) : geo.usableHeightPx,\n blockGap: BLOCK_GAP_PX,\n })\n\n return (\n <div data-resume-document>\n {measureLayer}\n <div className=\"doc-pages\" style={{ gap: geo.gapPx }}>\n {Array.from({ length: pack.pageCount }, (_, p) => {\n const sideOnPage = blocks.sidebar.filter(\n (_, i) => pack.pageOf.sidebar[`sidebar-${i}`] === p\n )\n const mainOnPage = blocks.main.filter((_, i) => pack.pageOf.main[`main-${i}`] === p)\n // Key the layout on the WHOLE document, not the current page: a\n // single-column doc (the CV — no sidebar at all) renders full\n // width, but a two-column doc keeps its grid on every page,\n // including continuation pages where the sidebar has run out, so\n // the main column stays in its right-hand track instead of\n // jumping to full width (which broke the 2-col layout on page 2+).\n const isTwoColumn = blocks.sidebar.length > 0\n return (\n <div\n className=\"doc-page\"\n data-resume-page\n key={`page-${String(p)}`}\n style={{\n width: geo.widthPx,\n height: geo.heightPx,\n overflow: 'hidden',\n padding: `${geo.padYPx}px ${geo.padXPx}px`,\n }}\n >\n {p === 0 && header}\n {isTwoColumn ? (\n <div className=\"doc-resume-grid\">\n <div className=\"doc-col doc-col-sidebar\">{sideOnPage}</div>\n <div className=\"doc-col doc-col-main\">{mainOnPage}</div>\n </div>\n ) : (\n <div className=\"doc-col\">{mainOnPage}</div>\n )}\n {p === pack.pageCount - 1 && footer}\n </div>\n )\n })}\n </div>\n <PageCountReporter count={pack.pageCount} report={report} />\n </div>\n )\n}\n\n/** Reports pageCount via an effect (no setState-during-render). */\nfunction PageCountReporter({ count, report }: { count: number; report: (n: number) => void }) {\n useEffect(() => {\n report(count)\n }, [count, report])\n return null\n}\n"]}
@@ -1,171 +1,3 @@
1
- /* src/styles/tokens.css */
2
- [data-resume-document] {
3
- --doc-meta-col: 11rem;
4
- --doc-resume-cols: 1fr 2fr;
5
- --doc-col-gap: 0.75rem;
6
- --doc-col-pad: 1.5rem;
7
- --doc-block-gap: 0.375rem;
8
- --doc-section-gap: 0.5rem;
9
- --doc-group-gap: 0.125rem;
10
- --doc-text: 10px;
11
- --doc-text-xs: 8px;
12
- --doc-leading: 1.4;
13
- --doc-leading-heading: 1.5;
14
- --doc-ink: #000;
15
- --doc-ink-body: #404040;
16
- --doc-ink-muted: #737373;
17
- --doc-ink-faint: #a3a3a3;
18
- --doc-rule: #d4d4d4;
19
- }
20
-
21
- /* src/styles/document.css */
22
- .doc-meta-grid {
23
- display: grid;
24
- min-width: 0;
25
- grid-template-columns: var(--doc-meta-col) minmax(0, 1fr);
26
- gap: var(--doc-col-gap);
27
- }
28
- .doc-resume-grid {
29
- display: grid;
30
- min-width: 0;
31
- grid-template-columns: var(--doc-resume-cols);
32
- }
33
- .doc-col {
34
- display: flex;
35
- min-width: 0;
36
- flex-direction: column;
37
- gap: var(--doc-block-gap);
38
- }
39
- .doc-group {
40
- display: flex;
41
- flex-direction: column;
42
- gap: var(--doc-group-gap);
43
- }
44
- .doc-section {
45
- margin-top: var(--doc-section-gap);
46
- }
47
- .doc-body {
48
- font-size: var(--doc-text);
49
- line-height: var(--doc-leading);
50
- color: var(--doc-ink-body);
51
- overflow-wrap: break-word;
52
- }
53
- .doc-meta {
54
- font-size: var(--doc-text);
55
- line-height: var(--doc-leading);
56
- color: var(--doc-ink-muted);
57
- }
58
- .doc-heading {
59
- font-size: var(--doc-text);
60
- line-height: var(--doc-leading-heading);
61
- color: var(--doc-ink);
62
- font-weight: 700;
63
- text-transform: uppercase;
64
- }
65
- .doc-title {
66
- font-size: var(--doc-text);
67
- line-height: 1;
68
- color: var(--doc-ink);
69
- font-weight: 700;
70
- text-transform: uppercase;
71
- }
72
- .doc-subheading {
73
- font-size: var(--doc-text);
74
- line-height: 1;
75
- color: var(--doc-ink);
76
- font-weight: 600;
77
- }
78
- .doc-strong {
79
- color: var(--doc-ink);
80
- font-weight: 600;
81
- }
82
- .doc-link {
83
- color: var(--doc-ink-body);
84
- text-decoration: underline;
85
- touch-action: manipulation;
86
- }
87
- .doc-rule {
88
- margin: 0.25rem 0;
89
- border-bottom: 1px solid var(--doc-rule);
90
- }
91
- .doc-footer {
92
- font-size: var(--doc-text-xs);
93
- color: var(--doc-ink-faint);
94
- margin-top: auto;
95
- display: flex;
96
- align-items: flex-end;
97
- justify-content: space-between;
98
- }
99
- .doc-footer a {
100
- color: inherit;
101
- }
102
- .doc-header {
103
- margin-bottom: 0.75rem;
104
- }
105
- .doc-header-col {
106
- display: flex;
107
- min-width: 0;
108
- flex-direction: column;
109
- justify-content: space-between;
110
- }
111
- .doc-header-left {
112
- padding-right: var(--doc-col-pad);
113
- }
114
- .doc-header-right {
115
- padding-left: var(--doc-col-pad);
116
- }
117
- .doc-header-right > p + p {
118
- margin-top: 0.125rem;
119
- }
120
- .doc-links {
121
- margin-top: 0.75rem;
122
- }
123
- .doc-links > p {
124
- margin-top: 0;
125
- color: var(--doc-ink-muted);
126
- }
127
- .doc-links a {
128
- color: inherit;
129
- }
130
- .doc-links em {
131
- color: var(--doc-ink-faint);
132
- }
133
- .doc-entry-body {
134
- min-width: 0;
135
- }
136
- .doc-col-sidebar {
137
- grid-column-start: 1;
138
- grid-row-start: 1;
139
- padding-right: var(--doc-col-pad);
140
- }
141
- .doc-col-main {
142
- grid-column-start: 2;
143
- grid-row-start: 1;
144
- padding-left: var(--doc-col-pad);
145
- }
146
- .doc-list {
147
- list-style: disc;
148
- padding-left: 0.75rem;
149
- }
150
- .doc-em {
151
- font-style: normal;
152
- }
153
- .doc-hr {
154
- margin: 0.75rem 0;
155
- }
156
- .doc-pages {
157
- display: flex;
158
- flex-direction: column;
159
- }
160
- .doc-page {
161
- position: relative;
162
- display: flex;
163
- flex-direction: column;
164
- background: #fff;
165
- color: #000;
166
- box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
167
- }
168
-
169
1
  /* src/editor/editor.css */
170
2
  .resume-editor {
171
3
  display: flex;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/styles/tokens.css","../../src/styles/document.css","../../src/editor/editor.css"],"sourcesContent":["/*\n * @atom63/resume — document design tokens (the --doc-* vocabulary).\n *\n * The single source of truth for the resume/CV look. Override any token (e.g.\n * in your own stylesheet, scoped to [data-resume-document]) to restyle the\n * resume and CV together; the React primitives only compose these.\n *\n * Page SIZE is not a token — it is fixed numeric geometry (see geometry.ts) and\n * is selected with the ResumeViewer `pageSize` prop ('letter' | 'a4').\n *\n * Print-fixed by design: doc sizes are absolute px for PDF fidelity, independent\n * of any host typography-scale setting. The font *family* is inherited (so the\n * document follows the host font), which is why pagination re-measures on font\n * change.\n *\n * NOTE: --doc-block-gap MUST stay in sync with BLOCK_GAP_PX in geometry.ts (the\n * JS packer reads the same number to compute page breaks).\n */\n[data-resume-document] {\n /* Document layout */\n --doc-meta-col: 11rem; /* left meta/label column (header name, section label, year|role) */\n --doc-resume-cols: 1fr 2fr; /* resume sidebar | main split */\n --doc-col-gap: 0.75rem; /* gap between the meta column and content */\n --doc-col-pad: 1.5rem; /* resume two-column inner gutter */\n --doc-block-gap: 0.375rem; /* between blocks within a column (== BLOCK_GAP_PX) */\n --doc-section-gap: 0.5rem; /* space above a section */\n --doc-group-gap: 0.125rem; /* within a tight group (title + meta line) */\n\n /* Type */\n --doc-text: 10px;\n --doc-text-xs: 8px;\n --doc-leading: 1.4;\n --doc-leading-heading: 1.5;\n\n /* Ink (on the white page) */\n --doc-ink: #000; /* headings, strong */\n --doc-ink-body: #404040; /* body copy (neutral-700) */\n --doc-ink-muted: #737373; /* meta / labels (neutral-500) */\n --doc-ink-faint: #a3a3a3; /* footer, faint detail (neutral-400) */\n --doc-rule: #d4d4d4; /* dividers (neutral-300) */\n}\n","/*\n * Resume & CV document layout + type primitives. These classes only COMPOSE the\n * design tokens — the token vocabulary itself (the paper and doc custom\n * properties) lives in tokens.css (imported separately, or together via\n * styles.css). Keep this file token-free so consumers can adopt just the tokens,\n * or restyle without forking these classes.\n */\n\n/* Layout primitives */\n.doc-meta-grid {\n display: grid;\n min-width: 0;\n grid-template-columns: var(--doc-meta-col) minmax(0, 1fr);\n gap: var(--doc-col-gap);\n}\n.doc-resume-grid {\n display: grid;\n min-width: 0;\n grid-template-columns: var(--doc-resume-cols);\n}\n.doc-col {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--doc-block-gap);\n}\n.doc-group {\n display: flex;\n flex-direction: column;\n gap: var(--doc-group-gap);\n}\n.doc-section {\n margin-top: var(--doc-section-gap);\n}\n\n/* Type primitives */\n.doc-body {\n font-size: var(--doc-text);\n line-height: var(--doc-leading);\n color: var(--doc-ink-body);\n overflow-wrap: break-word;\n}\n.doc-meta {\n font-size: var(--doc-text);\n line-height: var(--doc-leading);\n color: var(--doc-ink-muted);\n}\n.doc-heading {\n font-size: var(--doc-text);\n line-height: var(--doc-leading-heading);\n color: var(--doc-ink);\n font-weight: 700;\n text-transform: uppercase;\n}\n.doc-title {\n font-size: var(--doc-text);\n line-height: 1;\n color: var(--doc-ink);\n font-weight: 700;\n text-transform: uppercase;\n}\n.doc-subheading {\n font-size: var(--doc-text);\n line-height: 1;\n color: var(--doc-ink);\n font-weight: 600;\n}\n.doc-strong {\n color: var(--doc-ink);\n font-weight: 600;\n}\n.doc-link {\n color: var(--doc-ink-body);\n text-decoration: underline;\n /* touch-manipulation equivalent for links */\n touch-action: manipulation;\n}\n.doc-rule {\n margin: 0.25rem 0;\n border-bottom: 1px solid var(--doc-rule);\n}\n.doc-footer {\n font-size: var(--doc-text-xs);\n color: var(--doc-ink-faint);\n /* Layout (replacing Tailwind utilities) */\n margin-top: auto;\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n}\n.doc-footer a {\n color: inherit;\n}\n\n/* Header / layout helpers (replacing Tailwind utilities) */\n.doc-header {\n margin-bottom: 0.75rem;\n}\n.doc-header-col {\n display: flex;\n min-width: 0;\n flex-direction: column;\n justify-content: space-between;\n}\n.doc-header-left {\n padding-right: var(--doc-col-pad);\n}\n.doc-header-right {\n padding-left: var(--doc-col-pad);\n}\n.doc-header-right > p + p {\n margin-top: 0.125rem;\n}\n\n.doc-links {\n margin-top: 0.75rem;\n}\n.doc-links > p {\n margin-top: 0;\n color: var(--doc-ink-muted);\n}\n.doc-links a {\n color: inherit;\n}\n.doc-links em {\n color: var(--doc-ink-faint);\n}\n\n.doc-entry-body {\n min-width: 0;\n}\n\n/* Two-column grid placement (sidebar | main), used on every page incl. continuations */\n.doc-col-sidebar {\n grid-column-start: 1;\n grid-row-start: 1;\n padding-right: var(--doc-col-pad);\n}\n.doc-col-main {\n grid-column-start: 2;\n grid-row-start: 1;\n padding-left: var(--doc-col-pad);\n}\n\n.doc-list {\n list-style: disc;\n padding-left: 0.75rem;\n}\n.doc-em {\n font-style: normal;\n}\n.doc-hr {\n margin: 0.75rem 0;\n}\n\n/* Page frame (Tailwind shadow-lg + bg-white + text-black + flex column) */\n.doc-pages {\n display: flex;\n flex-direction: column;\n}\n.doc-page {\n position: relative;\n display: flex;\n flex-direction: column;\n background: #fff;\n color: #000;\n box-shadow:\n 0 10px 15px -3px rgb(0 0 0 / 0.1),\n 0 4px 6px -4px rgb(0 0 0 / 0.1);\n}\n","/* packages/resume/src/editor/editor.css\n Minimal, Tailwind-free layout for the split-pane resume editor. */\n\n.resume-editor {\n display: flex;\n flex-direction: row;\n width: 100%;\n height: 100%;\n min-height: 0;\n}\n\n.resume-editor-pane {\n flex: 1 1 50%;\n min-width: 0;\n min-height: 0;\n overflow: auto;\n}\n\n.resume-editor-source {\n display: block;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n resize: none;\n border: none;\n outline: none;\n padding: 1rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.8125rem;\n line-height: 1.5;\n tab-size: 2;\n}\n\n.resume-editor-preview {\n border-left: 1px solid rgba(0, 0, 0, 0.1);\n}\n\n.resume-mdx-live-empty {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 2rem;\n font-size: 0.875rem;\n opacity: 0.6;\n}\n\n.resume-mdx-live-error {\n padding: 1rem;\n font-size: 0.875rem;\n color: #b00020;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/editor/editor.css"],"sourcesContent":["/* packages/resume/src/editor/editor.css\n Minimal, Tailwind-free layout for the split-pane resume editor. */\n\n.resume-editor {\n display: flex;\n flex-direction: row;\n width: 100%;\n height: 100%;\n min-height: 0;\n}\n\n.resume-editor-pane {\n flex: 1 1 50%;\n min-width: 0;\n min-height: 0;\n overflow: auto;\n}\n\n.resume-editor-source {\n display: block;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n resize: none;\n border: none;\n outline: none;\n padding: 1rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.8125rem;\n line-height: 1.5;\n tab-size: 2;\n}\n\n.resume-editor-preview {\n border-left: 1px solid rgba(0, 0, 0, 0.1);\n}\n\n.resume-mdx-live-empty {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 2rem;\n font-size: 0.875rem;\n opacity: 0.6;\n}\n\n.resume-mdx-live-error {\n padding: 1rem;\n font-size: 0.875rem;\n color: #b00020;\n}\n"],"mappings":";AAGA,CAAC;AACC,WAAS;AACT,kBAAgB;AAChB,SAAO;AACP,UAAQ;AACR,cAAY;AACd;AAEA,CAAC;AACC,QAAM,EAAE,EAAE;AACV,aAAW;AACX,cAAY;AACZ,YAAU;AACZ;AAEA,CAAC;AACC,WAAS;AACT,SAAO;AACP,UAAQ;AACR,cAAY;AACZ,UAAQ;AACR,UAAQ;AACR,WAAS;AACT,WAAS;AACT;AAAA,IAAa,YAAY;AAAA,IAAE,cAAc;AAAA,IAAE,KAAK;AAAA,IAAE,MAAM;AAAA,IAAE,QAAQ;AAAA,IAAE;AACpE,aAAW;AACX,eAAa;AACb,YAAU;AACZ;AAEA,CAAC;AACC,eAAa,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACvC;AAEA,CAAC;AACC,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,UAAQ;AACR,WAAS;AACT,aAAW;AACX,WAAS;AACX;AAEA,CAAC;AACC,WAAS;AACT,aAAW;AACX,SAAO;AACT;","names":[]}
@@ -1,4 +1,4 @@
1
- import { resumeMdxComponents } from '../chunk-ARBKVUHN.js';
1
+ import { resumeMdxComponents } from '../chunk-V7BVTGX3.js';
2
2
  import { MDXProvider } from '@mdx-js/react';
3
3
  import { useEffect, useState, useRef, Component } from 'react';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { getPageGeometry, ResumePageSizeContext, ResumeFontFamilyContext, PaginationReportContext, resumeMdxComponents, WRAPPER_PADDING_X } from './chunk-ARBKVUHN.js';
2
- export { BLOCK_GAP_PX, Columns, Entry, Footer, Group, Header, Main, PAGE, PaginatedResume, PaginationReportContext, ResumeFontFamilyContext, ResumePageSizeContext, Rule, Section, Sidebar, getPageGeometry, packIntoPages, resumeMdxComponents, usePaginationReport, useResumeFontFamily, useResumePageSize } from './chunk-ARBKVUHN.js';
1
+ import { getPageGeometry, resumeMdxComponents, ResumePageSizeContext, ResumeFontFamilyContext, PaginationReportContext, WRAPPER_PADDING_X } from './chunk-V7BVTGX3.js';
2
+ export { BLOCK_GAP_PX, Columns, Entry, Footer, Group, Header, Main, PAGE, PaginatedResume, PaginationReportContext, ResumeFontFamilyContext, ResumePageSizeContext, Rule, Section, Sidebar, getPageGeometry, packIntoPages, resumeMdxComponents, usePaginationReport, useResumeFontFamily, useResumePageSize } from './chunk-V7BVTGX3.js';
3
3
  import { MDXProvider } from '@mdx-js/react';
4
4
  import clsx from 'clsx';
5
5
  import { Maximize2, Minus, Plus, ClipboardCopy } from 'lucide-react';
@@ -478,6 +478,7 @@ function ResumeViewer({
478
478
  const isMobile = useIsMobile();
479
479
  const scrollRef = useRef(null);
480
480
  const contentRef = useRef(null);
481
+ const mdxComponents = { ...resumeMdxComponents, ...components };
481
482
  const {
482
483
  pageCount,
483
484
  setPageCount,
@@ -578,7 +579,7 @@ function ResumeViewer({
578
579
  /* @__PURE__ */ jsx(
579
580
  "button",
580
581
  {
581
- className: "resume-viewer-btn resume-viewer-btn-text",
582
+ className: "resume-viewer-btn resume-viewer-btn-primary",
582
583
  onClick: requestPrint,
583
584
  type: "button",
584
585
  children: "Save to PDF"
@@ -619,7 +620,7 @@ function ResumeViewer({
619
620
  height: totalHeight,
620
621
  transform: effectiveScale === 1 ? void 0 : `scale(${effectiveScale})`
621
622
  },
622
- children: /* @__PURE__ */ jsx(ResumePageSizeContext.Provider, { value: pageSize, children: /* @__PURE__ */ jsx(ResumeFontFamilyContext.Provider, { value: fontFamily, children: /* @__PURE__ */ jsx(PaginationReportContext.Provider, { value: setPageCount, children: /* @__PURE__ */ jsx(MDXProvider, { components: components ?? resumeMdxComponents, children: /* @__PURE__ */ jsx(
623
+ children: /* @__PURE__ */ jsx(ResumePageSizeContext.Provider, { value: pageSize, children: /* @__PURE__ */ jsx(ResumeFontFamilyContext.Provider, { value: fontFamily, children: /* @__PURE__ */ jsx(PaginationReportContext.Provider, { value: setPageCount, children: /* @__PURE__ */ jsx(MDXProvider, { components: mdxComponents, children: /* @__PURE__ */ jsx(
623
624
  "div",
624
625
  {
625
626
  className: "resume-viewer-content",