@freereportjs/core 0.1.0 → 0.9.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/dist/cdn/freereport.css +168 -168
- package/dist/cdn/freereport.esm.js +45 -45
- package/dist/cdn/freereport.min.js +46 -46
- package/dist/index.d.ts +24 -2
- package/dist/index.js +57 -11
- package/dist/styles.css +168 -168
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -616,6 +616,12 @@ interface AgentStatus {
|
|
|
616
616
|
port: number;
|
|
617
617
|
/** True when this origin's stored token is valid. */
|
|
618
618
|
paired: boolean;
|
|
619
|
+
/** Newer agent version the agent has found (it installs itself when idle), or null. Always null for agents before 1.1.0. */
|
|
620
|
+
updateAvailable: string | null;
|
|
621
|
+
/** Newest version from the agent's last update check, or null when it has not checked (or is older than 1.1.0). */
|
|
622
|
+
latestVersion: string | null;
|
|
623
|
+
/** True when this agent is older than the minimum supported version: ask the user to update. */
|
|
624
|
+
outdated: boolean;
|
|
619
625
|
}
|
|
620
626
|
/** One installed printer (`GET /v1/printers`). */
|
|
621
627
|
interface AgentPrinter {
|
|
@@ -695,6 +701,7 @@ declare const agent: {
|
|
|
695
701
|
/**
|
|
696
702
|
* Find a running agent on 127.0.0.1 (ports 18731–18735, 600 ms each, tried in parallel).
|
|
697
703
|
* Resolves to its status, or null when it is not installed / not running.
|
|
704
|
+
* `status.updateAvailable` / `latestVersion` / `outdated` report the agent's self-update state.
|
|
698
705
|
*/
|
|
699
706
|
detect(): Promise<AgentStatus | null>;
|
|
700
707
|
/**
|
|
@@ -788,6 +795,21 @@ interface ViewerOptions extends ReportOptions {
|
|
|
788
795
|
/** Show the parameter panel open at start (default: when the report has parameters without defaults). */
|
|
789
796
|
paramsOpen?: boolean;
|
|
790
797
|
fileName?: string;
|
|
798
|
+
/** After every successful run (start, 조회/Run, setData, setParams, setDefinition): page and row counts. */
|
|
799
|
+
onReady?: (e: ViewerReadyEvent) => void;
|
|
800
|
+
/** When the user submits the parameter panel, before the data is fetched. Return false to stay (e.g. failed validation), or return changed params. */
|
|
801
|
+
onParamsSubmit?: (params: Record<string, unknown>) => boolean | void | Record<string, unknown> | Promise<boolean | void | Record<string, unknown>>;
|
|
802
|
+
/** The page in view changed (1-based). */
|
|
803
|
+
onPageChange?: (page: number, total: number) => void;
|
|
804
|
+
/** Loading data, laying out, printing or saving failed. The viewer still shows its own message. */
|
|
805
|
+
onError?: (error: Error, during: 'data' | 'layout' | 'output') => void;
|
|
806
|
+
}
|
|
807
|
+
interface ViewerReadyEvent {
|
|
808
|
+
pages: number;
|
|
809
|
+
rows: number;
|
|
810
|
+
/** Layout time in milliseconds. */
|
|
811
|
+
ms: number;
|
|
812
|
+
params: Record<string, unknown>;
|
|
791
813
|
}
|
|
792
814
|
interface Viewer {
|
|
793
815
|
readonly report: Report;
|
|
@@ -1123,7 +1145,7 @@ declare function verifyLicense(key: string, host: string, opts?: {
|
|
|
1123
1145
|
declare function setLicenseKey(key: string): void;
|
|
1124
1146
|
|
|
1125
1147
|
/** FreeReport version (kept in sync with releases.json by scripts/release.mjs). */
|
|
1126
|
-
declare const version = "0.
|
|
1148
|
+
declare const version = "0.9.0";
|
|
1127
1149
|
|
|
1128
1150
|
type Lang = 'ko' | 'en';
|
|
1129
1151
|
|
|
@@ -1185,4 +1207,4 @@ declare function renderXlsx(def: ReportDefinition, data?: ReportData, opts?: Ser
|
|
|
1185
1207
|
mode?: 'form' | 'data';
|
|
1186
1208
|
}): Promise<Uint8Array>;
|
|
1187
1209
|
|
|
1188
|
-
export { AgentError, type AgentLogEntry, type AgentPrintOptions, type AgentPrintResult, type AgentPrinter, type AgentStatus, type Align, type Band, type BandKind, type BarcodeElement, type BorderInput, type BorderSide, type BoxItem, type ChartElement, type ChartSeries, type CrosstabElement, type Designer, type DesignerOptions, type ElementType, type Emboss, type Expr, FUNCTIONS, type FieldElement, type FontBytes, type FontEntry, type GroupDefinition, type ImageElement, type ImageItem, type ItemSource, type LayoutOptions, type LayoutResult, type LicenseInfo, type LineElement, type LineItem, type OutputEvent, type OutputKind, PAPER, type PageItem, type PageSetup, type PaperSize, type ParamDefinition, type PathCommand, type PathItem, type PdfFontSource, type PdfOptions, type PdfPermissions, type PdfSecurity, type PrintOptions, type RectElement, type Report, type ReportData, type ReportDefinition, type ReportElement, type ReportOptions, type ReportPage, type ResolvedBorder, type ResolvedFont, type ServerRenderOptions, type Style, type TableColumn, type TableElement, type TextElement, type TextItem, type TextLine, type TextMeasurer, type VAlign, type Viewer, type ViewerOptions, type Watermark, type XCell, type XCellStyle, type XSheet, agent, applyEmboss, blankReport, canonicalText, canvasMeasurer, checkExpression, compile, contentWidth, createDesigner, createReport, createViewer, dataToCsv, dataToXlsx, defaultMeasurer, embossImage, encodeCode128, encodeDataMatrix, encodeEan13, encodePdf417, encodeQr, ensureFonts, estimateMeasurer, evaluate, fingerprintPages, formatDate, formatNumber, formatValue, getFont, interpolate, koreanAmount, koreanNumber, layoutReport, loadFontBytes, loadFonts, pageGeometry, pageToSvg, pagesToHwpx, pagesToXlsx, paramValues, printPages, registerFont, renderPage, renderPdf, renderXlsx, resetMeasurer, rowsOf, saveFile, setLicenseKey, sha256Hex, ttfMeasurer, verifyLicense, version, wrapText, writePdf, writeXlsx };
|
|
1210
|
+
export { AgentError, type AgentLogEntry, type AgentPrintOptions, type AgentPrintResult, type AgentPrinter, type AgentStatus, type Align, type Band, type BandKind, type BarcodeElement, type BorderInput, type BorderSide, type BoxItem, type ChartElement, type ChartSeries, type CrosstabElement, type Designer, type DesignerOptions, type ElementType, type Emboss, type Expr, FUNCTIONS, type FieldElement, type FontBytes, type FontEntry, type GroupDefinition, type ImageElement, type ImageItem, type ItemSource, type LayoutOptions, type LayoutResult, type LicenseInfo, type LineElement, type LineItem, type OutputEvent, type OutputKind, PAPER, type PageItem, type PageSetup, type PaperSize, type ParamDefinition, type PathCommand, type PathItem, type PdfFontSource, type PdfOptions, type PdfPermissions, type PdfSecurity, type PrintOptions, type RectElement, type Report, type ReportData, type ReportDefinition, type ReportElement, type ReportOptions, type ReportPage, type ResolvedBorder, type ResolvedFont, type ServerRenderOptions, type Style, type TableColumn, type TableElement, type TextElement, type TextItem, type TextLine, type TextMeasurer, type VAlign, type Viewer, type ViewerOptions, type ViewerReadyEvent, type Watermark, type XCell, type XCellStyle, type XSheet, agent, applyEmboss, blankReport, canonicalText, canvasMeasurer, checkExpression, compile, contentWidth, createDesigner, createReport, createViewer, dataToCsv, dataToXlsx, defaultMeasurer, embossImage, encodeCode128, encodeDataMatrix, encodeEan13, encodePdf417, encodeQr, ensureFonts, estimateMeasurer, evaluate, fingerprintPages, formatDate, formatNumber, formatValue, getFont, interpolate, koreanAmount, koreanNumber, layoutReport, loadFontBytes, loadFonts, pageGeometry, pageToSvg, pagesToHwpx, pagesToXlsx, paramValues, printPages, registerFont, renderPage, renderPdf, renderXlsx, resetMeasurer, rowsOf, saveFile, setLicenseKey, sha256Hex, ttfMeasurer, verifyLicense, version, wrapText, writePdf, writeXlsx };
|
package/dist/index.js
CHANGED
|
@@ -187,8 +187,8 @@ function pdfFonts(pages) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
// src/version.ts
|
|
190
|
-
var version = "0.
|
|
191
|
-
var releaseDate = "2026-10-
|
|
190
|
+
var version = "0.9.0";
|
|
191
|
+
var releaseDate = "2026-10-16";
|
|
192
192
|
|
|
193
193
|
// src/license.ts
|
|
194
194
|
var PUBLIC_KEY = { kty: "EC", crv: "P-256", x: "MiJXJR8TZJ_-0VKk0wIQ-5mzRsyQ6ruGsbcRRdw9jrw", y: "MTdklYSzCM2pganffz7PPMfxSclQkBLqU_9se_VDznM" };
|
|
@@ -5365,6 +5365,14 @@ html, body { margin: 0; padding: 0; background: #fff; }
|
|
|
5365
5365
|
}
|
|
5366
5366
|
|
|
5367
5367
|
// src/agent.ts
|
|
5368
|
+
function normalizeStatus(s) {
|
|
5369
|
+
return {
|
|
5370
|
+
...s,
|
|
5371
|
+
updateAvailable: typeof s.updateAvailable === "string" ? s.updateAvailable : null,
|
|
5372
|
+
latestVersion: typeof s.latestVersion === "string" ? s.latestVersion : null,
|
|
5373
|
+
outdated: s.outdated === true
|
|
5374
|
+
};
|
|
5375
|
+
}
|
|
5368
5376
|
var AgentError = class extends Error {
|
|
5369
5377
|
constructor(message, code, status) {
|
|
5370
5378
|
super(message);
|
|
@@ -5412,7 +5420,7 @@ async function fetchJson(url, init = {}) {
|
|
|
5412
5420
|
async function probe(port) {
|
|
5413
5421
|
const s = await fetchJson(`http://127.0.0.1:${port}/v1/status`, { timeout: DETECT_TIMEOUT });
|
|
5414
5422
|
if (s?.name !== AGENT_NAME) throw new Error("not the agent");
|
|
5415
|
-
return s;
|
|
5423
|
+
return normalizeStatus(s);
|
|
5416
5424
|
}
|
|
5417
5425
|
async function requireBase() {
|
|
5418
5426
|
if (base) return base;
|
|
@@ -5442,12 +5450,13 @@ var agent = {
|
|
|
5442
5450
|
/**
|
|
5443
5451
|
* Find a running agent on 127.0.0.1 (ports 18731–18735, 600 ms each, tried in parallel).
|
|
5444
5452
|
* Resolves to its status, or null when it is not installed / not running.
|
|
5453
|
+
* `status.updateAvailable` / `latestVersion` / `outdated` report the agent's self-update state.
|
|
5445
5454
|
*/
|
|
5446
5455
|
async detect() {
|
|
5447
5456
|
if (typeof fetch === "undefined") return null;
|
|
5448
5457
|
if (base) {
|
|
5449
5458
|
try {
|
|
5450
|
-
return await fetchJson(`${base}/v1/status`, { timeout: DETECT_TIMEOUT });
|
|
5459
|
+
return normalizeStatus(await fetchJson(`${base}/v1/status`, { timeout: DETECT_TIMEOUT }));
|
|
5451
5460
|
} catch {
|
|
5452
5461
|
base = null;
|
|
5453
5462
|
}
|
|
@@ -5850,6 +5859,27 @@ function createViewer(el, options) {
|
|
|
5850
5859
|
const pageH = result.height * MM_PX * scale + PAGE_GAP;
|
|
5851
5860
|
current = Math.min(result.pages.length - 1, Math.max(0, Math.round(body.scrollTop / pageH)));
|
|
5852
5861
|
if (pageInput && document.activeElement !== pageInput) pageInput.value = String(current + 1);
|
|
5862
|
+
notifyPage();
|
|
5863
|
+
};
|
|
5864
|
+
let reported = -1;
|
|
5865
|
+
const notifyPage = () => {
|
|
5866
|
+
if (!result?.pages.length || current === reported) return;
|
|
5867
|
+
reported = current;
|
|
5868
|
+
try {
|
|
5869
|
+
options.onPageChange?.(current + 1, result.pages.length);
|
|
5870
|
+
} catch (e) {
|
|
5871
|
+
console.error(e);
|
|
5872
|
+
}
|
|
5873
|
+
};
|
|
5874
|
+
const fail = (e, during) => {
|
|
5875
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
5876
|
+
console.error(err);
|
|
5877
|
+
try {
|
|
5878
|
+
options.onError?.(err, during);
|
|
5879
|
+
} catch (x) {
|
|
5880
|
+
console.error(x);
|
|
5881
|
+
}
|
|
5882
|
+
return err;
|
|
5853
5883
|
};
|
|
5854
5884
|
const goTo = (n2) => {
|
|
5855
5885
|
if (!result) return;
|
|
@@ -5858,6 +5888,7 @@ function createViewer(el, options) {
|
|
|
5858
5888
|
if (holder) body.scrollTop = holder.offsetTop - pagesEl.offsetTop;
|
|
5859
5889
|
current = i;
|
|
5860
5890
|
if (pageInput) pageInput.value = String(i + 1);
|
|
5891
|
+
notifyPage();
|
|
5861
5892
|
};
|
|
5862
5893
|
const setZoom = (z) => {
|
|
5863
5894
|
const ratio = result ? body.scrollTop / Math.max(1, body.scrollHeight) : 0;
|
|
@@ -5869,20 +5900,28 @@ function createViewer(el, options) {
|
|
|
5869
5900
|
const run = async () => {
|
|
5870
5901
|
const seq2 = ++runSeq;
|
|
5871
5902
|
busy(t.loading);
|
|
5903
|
+
let during = "data";
|
|
5872
5904
|
try {
|
|
5873
5905
|
if (options.fetchData) {
|
|
5874
5906
|
const fetched = await options.fetchData(params);
|
|
5875
5907
|
if (seq2 !== runSeq) return;
|
|
5876
5908
|
report.setData(fetched);
|
|
5877
5909
|
}
|
|
5910
|
+
during = "layout";
|
|
5878
5911
|
report.setParams(params);
|
|
5879
5912
|
await ensureFonts(report.definition);
|
|
5880
5913
|
if (destroyed) return;
|
|
5881
5914
|
result = report.layout();
|
|
5915
|
+
reported = -1;
|
|
5882
5916
|
build();
|
|
5917
|
+
try {
|
|
5918
|
+
options.onReady?.({ pages: result.pages.length, rows: result.rowCount, ms: result.ms, params: { ...params } });
|
|
5919
|
+
} catch (e) {
|
|
5920
|
+
console.error(e);
|
|
5921
|
+
}
|
|
5883
5922
|
} catch (e) {
|
|
5884
|
-
|
|
5885
|
-
pagesEl.innerHTML = `<p class="fr-empty">${t.error}: ${escapeHtml(
|
|
5923
|
+
const err = fail(e, during);
|
|
5924
|
+
pagesEl.innerHTML = `<p class="fr-empty">${t.error}: ${escapeHtml(err.message)}</p>`;
|
|
5886
5925
|
} finally {
|
|
5887
5926
|
busy(null);
|
|
5888
5927
|
}
|
|
@@ -5892,8 +5931,7 @@ function createViewer(el, options) {
|
|
|
5892
5931
|
try {
|
|
5893
5932
|
await report.download(kind, options.fileName);
|
|
5894
5933
|
} catch (e) {
|
|
5895
|
-
|
|
5896
|
-
alertText(`${t.error}: ${e.message}`);
|
|
5934
|
+
alertText(`${t.error}: ${fail(e, "output").message}`);
|
|
5897
5935
|
} finally {
|
|
5898
5936
|
busy(null);
|
|
5899
5937
|
}
|
|
@@ -5935,7 +5973,7 @@ function createViewer(el, options) {
|
|
|
5935
5973
|
setZoom(Math.round((scale - 0.1) * 10) / 10);
|
|
5936
5974
|
break;
|
|
5937
5975
|
case "print":
|
|
5938
|
-
void report.print().catch((err) => alertText(`${t.error}: ${err.message}`));
|
|
5976
|
+
void report.print().catch((err) => alertText(`${t.error}: ${fail(err, "output").message}`));
|
|
5939
5977
|
break;
|
|
5940
5978
|
case "pdf":
|
|
5941
5979
|
void exportAs("pdf");
|
|
@@ -6010,7 +6048,7 @@ function createViewer(el, options) {
|
|
|
6010
6048
|
e.preventDefault();
|
|
6011
6049
|
setZoom(Math.round(scale * (e.deltaY < 0 ? 1.1 : 1 / 1.1) * 100) / 100);
|
|
6012
6050
|
}, { passive: false });
|
|
6013
|
-
form?.addEventListener("submit", (e) => {
|
|
6051
|
+
form?.addEventListener("submit", async (e) => {
|
|
6014
6052
|
e.preventDefault();
|
|
6015
6053
|
const next = { ...params };
|
|
6016
6054
|
form.querySelectorAll("input, select").forEach((inp) => {
|
|
@@ -6018,7 +6056,15 @@ function createViewer(el, options) {
|
|
|
6018
6056
|
const v = inp.value;
|
|
6019
6057
|
next[inp.name] = type === "number" ? v === "" ? null : Number(v) : type === "boolean" ? v === "true" : v;
|
|
6020
6058
|
});
|
|
6021
|
-
|
|
6059
|
+
let answer;
|
|
6060
|
+
try {
|
|
6061
|
+
answer = await options.onParamsSubmit?.({ ...next });
|
|
6062
|
+
} catch (x) {
|
|
6063
|
+
fail(x, "data");
|
|
6064
|
+
return;
|
|
6065
|
+
}
|
|
6066
|
+
if (answer === false) return;
|
|
6067
|
+
params = answer && typeof answer === "object" ? { ...next, ...answer } : next;
|
|
6022
6068
|
void run();
|
|
6023
6069
|
});
|
|
6024
6070
|
const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
package/dist/styles.css
CHANGED
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
/* FreeReport viewer and designer. Override the --fr-* variables to theme. */
|
|
2
|
-
.fr-viewer, .fr-designer {
|
|
3
|
-
--fr-bg: #e9ecf1;
|
|
4
|
-
--fr-panel: #ffffff;
|
|
5
|
-
--fr-ink: #0e1726;
|
|
6
|
-
--fr-ink-2: #4a5568;
|
|
7
|
-
--fr-rule: #d5dbe3;
|
|
8
|
-
--fr-accent: #2340f5;
|
|
9
|
-
--fr-accent-ink: #ffffff;
|
|
10
|
-
--fr-hover: #f1f3f7;
|
|
11
|
-
--fr-radius: 6px;
|
|
12
|
-
--fr-font: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", "Segoe UI", sans-serif;
|
|
13
|
-
display: flex; flex-direction: column; min-height: 0; height: 100%;
|
|
14
|
-
font: 13px/1.4 var(--fr-font); color: var(--fr-ink); background: var(--fr-bg);
|
|
15
|
-
border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); overflow: hidden; box-sizing: border-box;
|
|
16
|
-
}
|
|
17
|
-
.fr-viewer *, .fr-designer * { box-sizing: border-box; }
|
|
18
|
-
|
|
19
|
-
.fr-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 2px; padding: 6px 8px; background: var(--fr-panel); border-bottom: 1px solid var(--fr-rule); }
|
|
20
|
-
.fr-btn { display: inline-flex; align-items: center; gap: 5px; height: 30px; padding: 0 9px; border: 1px solid transparent; border-radius: var(--fr-radius); background: none; color: var(--fr-ink); font: inherit; font-weight: 500; cursor: pointer; white-space: nowrap; }
|
|
21
|
-
.fr-btn:hover { background: var(--fr-hover); }
|
|
22
|
-
.fr-btn:focus-visible, .fr-viewer select:focus-visible, .fr-viewer input:focus-visible { outline: 2px solid var(--fr-accent); outline-offset: 1px; }
|
|
23
|
-
.fr-btn:disabled { opacity: .45; cursor: default; }
|
|
24
|
-
.fr-btn.fr-icon { width: 30px; padding: 0; justify-content: center; }
|
|
25
|
-
.fr-btn.fr-primary { background: var(--fr-accent); color: var(--fr-accent-ink); }
|
|
26
|
-
.fr-btn.fr-primary:hover { filter: brightness(1.08); }
|
|
27
|
-
.fr-btn[aria-expanded="true"], .fr-btn[aria-pressed="true"] { background: var(--fr-hover); border-color: var(--fr-rule); }
|
|
28
|
-
.fr-btn svg { flex: none; }
|
|
29
|
-
.fr-sep { width: 1px; height: 20px; margin: 0 6px; background: var(--fr-rule); }
|
|
30
|
-
.fr-spacer { flex: 1; }
|
|
31
|
-
.fr-pageno { display: inline-flex; align-items: center; gap: 4px; margin: 0 4px; color: var(--fr-ink-2); font-variant-numeric: tabular-nums; }
|
|
32
|
-
.fr-pageno input { width: 44px; height: 28px; text-align: center; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); font: inherit; color: var(--fr-ink); }
|
|
33
|
-
.fr-zoom { height: 30px; padding: 0 6px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); background: var(--fr-panel); font: inherit; color: var(--fr-ink); }
|
|
34
|
-
.fr-menu { position: relative; }
|
|
35
|
-
.fr-menu-list { position: absolute; right: 0; top: calc(100% + 4px); z-index: 20; min-width: 180px; padding: 4px; background: var(--fr-panel); border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); box-shadow: 0 8px 24px rgba(14, 23, 38, .14); display: flex; flex-direction: column; }
|
|
36
|
-
.fr-menu-list[hidden] { display: none; }
|
|
37
|
-
.fr-menu-list button { text-align: left; padding: 8px 10px; border: 0; background: none; border-radius: 4px; font: inherit; color: var(--fr-ink); cursor: pointer; }
|
|
38
|
-
.fr-menu-list button:hover, .fr-menu-list button:focus-visible { background: var(--fr-hover); outline: none; }
|
|
39
|
-
|
|
40
|
-
.fr-params { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 14px; padding: 10px 12px; background: var(--fr-panel); border-bottom: 1px solid var(--fr-rule); }
|
|
41
|
-
.fr-params[hidden] { display: none; }
|
|
42
|
-
.fr-param { display: flex; flex-direction: column; gap: 3px; }
|
|
43
|
-
.fr-param label { font-size: 12px; color: var(--fr-ink-2); font-weight: 600; }
|
|
44
|
-
.fr-param label b { color: #c8102e; }
|
|
45
|
-
.fr-param input, .fr-param select { height: 30px; min-width: 140px; padding: 0 8px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); font: inherit; background: #fff; color: var(--fr-ink); }
|
|
46
|
-
|
|
47
|
-
.fr-body { position: relative; flex: 1; min-height: 0; overflow: auto; outline: none; }
|
|
48
|
-
.fr-pages { display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 16px 24px 32px; min-width: min-content; }
|
|
49
|
-
.fr-page { width: var(--fr-page-w, 794px); height: var(--fr-page-h, 1123px); flex: none; background: #fff; box-shadow: 0 1px 3px rgba(14, 23, 38, .18), 0 6px 18px -8px rgba(14, 23, 38, .25); }
|
|
50
|
-
.fr-page-svg { display: block; width: 100%; height: 100%; }
|
|
51
|
-
.fr-page { position: relative; }
|
|
52
|
-
.fr-hit { position: absolute; background: rgba(242, 169, 0, .38); outline: 2px solid #f2a900; border-radius: 2px; pointer-events: none; }
|
|
53
|
-
.fr-search { display: inline-flex; align-items: center; gap: 4px; height: 30px; padding: 0 8px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); color: var(--fr-ink-2); background: var(--fr-panel); }
|
|
54
|
-
.fr-search input { width: 120px; border: 0; outline: none; font: inherit; color: var(--fr-ink); background: none; }
|
|
55
|
-
.fr-search:focus-within { border-color: var(--fr-accent); }
|
|
56
|
-
.fr-search-count { font-size: 12px; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
57
|
-
.fr-empty { margin: 48px auto; color: var(--fr-ink-2); }
|
|
58
|
-
.fr-overlay { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 10px; background: rgba(233, 236, 241, .72); font-weight: 600; color: var(--fr-ink-2); z-index: 5; }
|
|
59
|
-
.fr-overlay[hidden] { display: none; }
|
|
60
|
-
.fr-spinner { width: 18px; height: 18px; border: 2px solid var(--fr-rule); border-top-color: var(--fr-accent); border-radius: 50%; animation: fr-spin .8s linear infinite; }
|
|
61
|
-
@keyframes fr-spin { to { transform: rotate(360deg); } }
|
|
62
|
-
@media (prefers-reduced-motion: reduce) { .fr-spinner { animation-duration: 2.4s; } }
|
|
63
|
-
.fr-status { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 4px 10px; background: var(--fr-panel); border-top: 1px solid var(--fr-rule); color: var(--fr-ink-2); font-size: 12px; font-variant-numeric: tabular-nums; min-height: 26px; }
|
|
64
|
-
.fr-badge { color: var(--fr-ink-2); text-decoration: none; border: 1px solid var(--fr-rule); border-radius: 999px; padding: 0 8px; }
|
|
65
|
-
.fr-badge[hidden] { display: none; }
|
|
66
|
-
|
|
67
|
-
@media (max-width: 640px) {
|
|
68
|
-
.fr-btn span { display: none; }
|
|
69
|
-
.fr-btn { padding: 0 7px; }
|
|
70
|
-
.fr-pages { padding: 10px 8px 24px; }
|
|
71
|
-
}
|
|
72
|
-
@media print {
|
|
73
|
-
.fr-viewer .fr-toolbar, .fr-viewer .fr-status, .fr-viewer .fr-params { display: none; }
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/* ── Designer ─────────────────────────────────── */
|
|
77
|
-
.fr-designer { outline: none; }
|
|
78
|
-
.fr-designer .fr-toolbar { gap: 1px; }
|
|
79
|
-
.fr-designer .fr-group { display: inline-flex; align-items: center; gap: 1px; flex-wrap: wrap; }
|
|
80
|
-
.fr-designer.is-preview .fr-design-only, .fr-designer.is-json .fr-design-only { display: none; }
|
|
81
|
-
.fr-tabs { display: inline-flex; padding: 2px; background: var(--fr-bg); border-radius: 7px; }
|
|
82
|
-
.fr-tab { height: 26px; padding: 0 12px; border: 0; border-radius: 5px; background: none; font: inherit; font-weight: 600; color: var(--fr-ink-2); cursor: pointer; }
|
|
83
|
-
.fr-tab[aria-selected="true"] { background: var(--fr-panel); color: var(--fr-ink); box-shadow: 0 1px 2px rgba(14, 23, 38, .12); }
|
|
84
|
-
.fr-zoom-label { min-width: 42px; text-align: center; font-variant-numeric: tabular-nums; color: var(--fr-ink-2); }
|
|
85
|
-
.fr-dz { flex: 1; min-height: 0; display: grid; grid-template-columns: 200px minmax(0, 1fr) 270px; }
|
|
86
|
-
.fr-designer.is-preview .fr-dz, .fr-designer.is-json .fr-dz { grid-template-columns: minmax(0, 1fr); }
|
|
87
|
-
.fr-designer.is-preview .fr-dz-left, .fr-designer.is-preview .fr-dz-right, .fr-designer.is-json .fr-dz-left, .fr-designer.is-json .fr-dz-right { display: none; }
|
|
88
|
-
.fr-dz-left, .fr-dz-right { background: var(--fr-panel); overflow: auto; min-height: 0; }
|
|
89
|
-
.fr-dz-left { border-right: 1px solid var(--fr-rule); padding: 8px; }
|
|
90
|
-
.fr-dz-right { border-left: 1px solid var(--fr-rule); }
|
|
91
|
-
.fr-dz-left h3 { margin: 10px 4px 6px; font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--fr-ink-2); }
|
|
92
|
-
.fr-dz-left h3:first-child { margin-top: 2px; }
|
|
93
|
-
.fr-dz-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
|
|
94
|
-
.fr-dz-tool { display: flex; align-items: center; gap: 6px; padding: 6px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); background: var(--fr-panel); font: inherit; font-size: 12px; color: var(--fr-ink); cursor: grab; text-align: left; }
|
|
95
|
-
.fr-dz-tool:hover, .fr-dz-field:hover { border-color: var(--fr-accent); color: var(--fr-accent); }
|
|
96
|
-
.fr-dz-fields { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
97
|
-
.fr-dz-field { padding: 3px 8px; border: 1px solid var(--fr-rule); border-radius: 999px; background: #f7f9fc; font: 12px/1.4 ui-monospace, Consolas, monospace; color: var(--fr-ink); cursor: grab; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
|
|
98
|
-
.fr-dz-empty { margin: 0 4px; color: var(--fr-ink-2); font-size: 12px; }
|
|
99
|
-
.fr-dz-bandopt { display: flex; align-items: center; gap: 6px; padding: 2px 4px; font-size: 12.5px; cursor: pointer; }
|
|
100
|
-
.fr-dz-groupopt { display: flex; align-items: center; justify-content: space-between; gap: 4px; padding: 2px 4px; font-size: 12px; }
|
|
101
|
-
.fr-dz-groupopt code { font-size: 11.5px; }
|
|
102
|
-
.fr-dz-addgroup { display: flex; gap: 4px; margin-top: 6px; }
|
|
103
|
-
.fr-dz-addgroup select { flex: 1; min-width: 0; height: 30px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); font: inherit; font-size: 12px; }
|
|
104
|
-
.fr-dz-addgroup .fr-btn span { font-size: 12px; }
|
|
105
|
-
.fr-dz-center { position: relative; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
|
|
106
|
-
.fr-dz-canvas { flex: 1; overflow: auto; padding: 24px 32px 64px; outline: none; }
|
|
107
|
-
.fr-dz-canvas[hidden], .fr-dz-preview[hidden], .fr-dz-json[hidden] { display: none; }
|
|
108
|
-
.fr-dz-page { margin: 0 auto; background: #fff; box-shadow: 0 1px 3px rgba(14, 23, 38, .16), 0 8px 24px -12px rgba(14, 23, 38, .3); user-select: none; }
|
|
109
|
-
.fr-dz-band { position: relative; }
|
|
110
|
-
.fr-dz-band-head { display: flex; justify-content: space-between; align-items: center; height: 20px; padding: 0 8px; background: #eef1f6; border-top: 1px solid var(--fr-rule); border-bottom: 1px solid var(--fr-rule); font-size: 11px; font-weight: 600; color: var(--fr-ink-2); cursor: pointer; }
|
|
111
|
-
.fr-dz-band-head small { font-weight: 500; font-variant-numeric: tabular-nums; }
|
|
112
|
-
.fr-dz-band.is-selected .fr-dz-band-head { background: #dfe6ff; color: var(--fr-accent); }
|
|
113
|
-
.fr-dz-band-area { position: relative; background-image: radial-gradient(circle, #d3d9e3 .8px, transparent .9px); overflow: visible; }
|
|
114
|
-
.fr-dz-band-resize { height: 5px; margin-top: -2px; position: relative; z-index: 3; cursor: ns-resize; }
|
|
115
|
-
.fr-dz-band-resize:hover { background: var(--fr-accent); opacity: .5; }
|
|
116
|
-
.fr-dz-hint { position: absolute; left: 8px; top: 50%; transform: translateY(-50%); color: #a6b0c0; font-size: 11px; pointer-events: none; white-space: nowrap; }
|
|
117
|
-
.fr-dz-el { position: absolute; cursor: move; outline: 1px dashed rgba(35, 64, 245, .18); }
|
|
118
|
-
.fr-dz-el:hover { outline-color: rgba(35, 64, 245, .55); }
|
|
119
|
-
.fr-dz-el.is-selected { outline: 1.5px solid var(--fr-accent); z-index: 2; }
|
|
120
|
-
.fr-dz-el.is-line { outline-offset: 2px; }
|
|
121
|
-
.fr-dz-el > * { pointer-events: none; }
|
|
122
|
-
.fr-dz-el > .fr-dz-h, .fr-dz-el > .fr-dz-inline { pointer-events: auto; }
|
|
123
|
-
.fr-dz-text { position: absolute; inset: 0; display: flex; flex-direction: column; overflow: hidden; white-space: pre-wrap; word-break: break-all; }
|
|
124
|
-
.fr-dz-text small { margin-left: 4px; font-size: 9px; color: #7a8599; font-weight: 400; }
|
|
125
|
-
.fr-dz-expr { color: #1a2fc0; }
|
|
126
|
-
.fr-dz-rect { position: absolute; inset: 0; }
|
|
127
|
-
.fr-dz-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
|
|
128
|
-
.fr-dz-el img { width: 100%; height: 100%; display: block; }
|
|
129
|
-
.fr-dz-ph { position: absolute; inset: 0; display: grid; place-items: center; background: repeating-linear-gradient(45deg, #f4f6fa, #f4f6fa 4px, #eceff5 4px, #eceff5 8px); color: #8a94a6; }
|
|
130
|
-
.fr-dz-h { position: absolute; width: 8px; height: 8px; background: #fff; border: 1.5px solid var(--fr-accent); border-radius: 2px; z-index: 3; }
|
|
131
|
-
.fr-dz-h-nw { left: -4px; top: -4px; cursor: nwse-resize; }
|
|
132
|
-
.fr-dz-h-n { left: calc(50% - 4px); top: -4px; cursor: ns-resize; }
|
|
133
|
-
.fr-dz-h-ne { right: -4px; top: -4px; cursor: nesw-resize; }
|
|
134
|
-
.fr-dz-h-e { right: -4px; top: calc(50% - 4px); cursor: ew-resize; }
|
|
135
|
-
.fr-dz-h-se { right: -4px; bottom: -4px; cursor: nwse-resize; }
|
|
136
|
-
.fr-dz-h-s { left: calc(50% - 4px); bottom: -4px; cursor: ns-resize; }
|
|
137
|
-
.fr-dz-h-sw { left: -4px; bottom: -4px; cursor: nesw-resize; }
|
|
138
|
-
.fr-dz-h-w { left: -4px; top: calc(50% - 4px); cursor: ew-resize; }
|
|
139
|
-
.fr-dz-marquee { position: absolute; border: 1px solid var(--fr-accent); background: rgba(35, 64, 245, .08); pointer-events: none; z-index: 4; }
|
|
140
|
-
.fr-dz-inline { position: absolute; inset: 0; min-height: 24px; z-index: 5; font: 13px/1.4 var(--fr-font); padding: 2px 4px; border: 2px solid var(--fr-accent); resize: none; }
|
|
141
|
-
.fr-dz-preview { flex: 1; min-height: 0; }
|
|
142
|
-
.fr-dz-preview .fr-viewer { border: 0; border-radius: 0; }
|
|
143
|
-
.fr-dz-json { flex: 1; min-height: 0; display: flex; flex-direction: column; }
|
|
144
|
-
.fr-dz-json textarea { flex: 1; border: 0; padding: 14px 16px; font: 12.5px/1.55 ui-monospace, "Cascadia Code", Consolas, monospace; resize: none; outline: none; background: #fbfcfe; color: var(--fr-ink); }
|
|
145
|
-
.fr-dz-json-bar { display: flex; justify-content: flex-end; align-items: center; gap: 12px; padding: 8px 12px; border-top: 1px solid var(--fr-rule); background: var(--fr-panel); }
|
|
146
|
-
.fr-dz-json-err { color: #c8102e; font-size: 12px; }
|
|
147
|
-
.fr-dz-props { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 4px 12px 24px; }
|
|
148
|
-
.fr-dz-sec { grid-column: 1 / -1; margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--fr-rule); font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--fr-ink-2); }
|
|
149
|
-
.fr-dz-sec:first-child { border-top: 0; margin-top: 4px; padding-top: 4px; }
|
|
150
|
-
.fr-dz-prop { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
|
|
151
|
-
.fr-dz-prop.is-wide { grid-column: 1 / -1; }
|
|
152
|
-
.fr-dz-prop.is-check { flex-direction: row; align-items: center; gap: 6px; grid-column: 1 / -1; font-size: 12.5px; cursor: pointer; }
|
|
153
|
-
.fr-dz-plabel { font-size: 11.5px; color: var(--fr-ink-2); font-weight: 600; }
|
|
154
|
-
.fr-dz-prop input[type=text], .fr-dz-prop input[type=number], .fr-dz-prop select, .fr-dz-prop textarea { width: 100%; height: 28px; padding: 0 7px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); font: inherit; font-size: 12.5px; color: var(--fr-ink); background: #fff; }
|
|
155
|
-
.fr-dz-prop textarea { height: auto; padding: 5px 7px; font-family: ui-monospace, Consolas, monospace; resize: vertical; }
|
|
156
|
-
.fr-dz-prop input.is-expr { font-family: ui-monospace, Consolas, monospace; }
|
|
157
|
-
.fr-dz-prop :focus-visible { outline: 2px solid var(--fr-accent); outline-offset: 0; }
|
|
158
|
-
.fr-dz-err { color: #c8102e; font-size: 11px; }
|
|
159
|
-
.fr-dz-err:empty { display: none; }
|
|
160
|
-
.fr-dz-color { display: flex; gap: 4px; }
|
|
161
|
-
.fr-dz-color input[type=color] { width: 30px; height: 28px; padding: 1px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); background: #fff; flex: none; }
|
|
162
|
-
.fr-dz-toggles { display: flex; gap: 3px; flex-wrap: wrap; }
|
|
163
|
-
.fr-dz-toggle { width: 30px; height: 28px; padding: 0; justify-content: center; border: 1px solid var(--fr-rule); font-weight: 700; }
|
|
164
|
-
.fr-dz-toggle[aria-pressed="true"] { background: #dfe6ff; border-color: var(--fr-accent); color: var(--fr-accent); }
|
|
165
|
-
@media (max-width: 960px) {
|
|
166
|
-
.fr-dz { grid-template-columns: 150px minmax(0, 1fr); }
|
|
167
|
-
.fr-dz-right { display: none; }
|
|
168
|
-
}
|
|
1
|
+
/* FreeReport viewer and designer. Override the --fr-* variables to theme. */
|
|
2
|
+
.fr-viewer, .fr-designer {
|
|
3
|
+
--fr-bg: #e9ecf1;
|
|
4
|
+
--fr-panel: #ffffff;
|
|
5
|
+
--fr-ink: #0e1726;
|
|
6
|
+
--fr-ink-2: #4a5568;
|
|
7
|
+
--fr-rule: #d5dbe3;
|
|
8
|
+
--fr-accent: #2340f5;
|
|
9
|
+
--fr-accent-ink: #ffffff;
|
|
10
|
+
--fr-hover: #f1f3f7;
|
|
11
|
+
--fr-radius: 6px;
|
|
12
|
+
--fr-font: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", "Segoe UI", sans-serif;
|
|
13
|
+
display: flex; flex-direction: column; min-height: 0; height: 100%;
|
|
14
|
+
font: 13px/1.4 var(--fr-font); color: var(--fr-ink); background: var(--fr-bg);
|
|
15
|
+
border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); overflow: hidden; box-sizing: border-box;
|
|
16
|
+
}
|
|
17
|
+
.fr-viewer *, .fr-designer * { box-sizing: border-box; }
|
|
18
|
+
|
|
19
|
+
.fr-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 2px; padding: 6px 8px; background: var(--fr-panel); border-bottom: 1px solid var(--fr-rule); }
|
|
20
|
+
.fr-btn { display: inline-flex; align-items: center; gap: 5px; height: 30px; padding: 0 9px; border: 1px solid transparent; border-radius: var(--fr-radius); background: none; color: var(--fr-ink); font: inherit; font-weight: 500; cursor: pointer; white-space: nowrap; }
|
|
21
|
+
.fr-btn:hover { background: var(--fr-hover); }
|
|
22
|
+
.fr-btn:focus-visible, .fr-viewer select:focus-visible, .fr-viewer input:focus-visible { outline: 2px solid var(--fr-accent); outline-offset: 1px; }
|
|
23
|
+
.fr-btn:disabled { opacity: .45; cursor: default; }
|
|
24
|
+
.fr-btn.fr-icon { width: 30px; padding: 0; justify-content: center; }
|
|
25
|
+
.fr-btn.fr-primary { background: var(--fr-accent); color: var(--fr-accent-ink); }
|
|
26
|
+
.fr-btn.fr-primary:hover { filter: brightness(1.08); }
|
|
27
|
+
.fr-btn[aria-expanded="true"], .fr-btn[aria-pressed="true"] { background: var(--fr-hover); border-color: var(--fr-rule); }
|
|
28
|
+
.fr-btn svg { flex: none; }
|
|
29
|
+
.fr-sep { width: 1px; height: 20px; margin: 0 6px; background: var(--fr-rule); }
|
|
30
|
+
.fr-spacer { flex: 1; }
|
|
31
|
+
.fr-pageno { display: inline-flex; align-items: center; gap: 4px; margin: 0 4px; color: var(--fr-ink-2); font-variant-numeric: tabular-nums; }
|
|
32
|
+
.fr-pageno input { width: 44px; height: 28px; text-align: center; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); font: inherit; color: var(--fr-ink); }
|
|
33
|
+
.fr-zoom { height: 30px; padding: 0 6px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); background: var(--fr-panel); font: inherit; color: var(--fr-ink); }
|
|
34
|
+
.fr-menu { position: relative; }
|
|
35
|
+
.fr-menu-list { position: absolute; right: 0; top: calc(100% + 4px); z-index: 20; min-width: 180px; padding: 4px; background: var(--fr-panel); border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); box-shadow: 0 8px 24px rgba(14, 23, 38, .14); display: flex; flex-direction: column; }
|
|
36
|
+
.fr-menu-list[hidden] { display: none; }
|
|
37
|
+
.fr-menu-list button { text-align: left; padding: 8px 10px; border: 0; background: none; border-radius: 4px; font: inherit; color: var(--fr-ink); cursor: pointer; }
|
|
38
|
+
.fr-menu-list button:hover, .fr-menu-list button:focus-visible { background: var(--fr-hover); outline: none; }
|
|
39
|
+
|
|
40
|
+
.fr-params { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 14px; padding: 10px 12px; background: var(--fr-panel); border-bottom: 1px solid var(--fr-rule); }
|
|
41
|
+
.fr-params[hidden] { display: none; }
|
|
42
|
+
.fr-param { display: flex; flex-direction: column; gap: 3px; }
|
|
43
|
+
.fr-param label { font-size: 12px; color: var(--fr-ink-2); font-weight: 600; }
|
|
44
|
+
.fr-param label b { color: #c8102e; }
|
|
45
|
+
.fr-param input, .fr-param select { height: 30px; min-width: 140px; padding: 0 8px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); font: inherit; background: #fff; color: var(--fr-ink); }
|
|
46
|
+
|
|
47
|
+
.fr-body { position: relative; flex: 1; min-height: 0; overflow: auto; outline: none; }
|
|
48
|
+
.fr-pages { display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 16px 24px 32px; min-width: min-content; }
|
|
49
|
+
.fr-page { width: var(--fr-page-w, 794px); height: var(--fr-page-h, 1123px); flex: none; background: #fff; box-shadow: 0 1px 3px rgba(14, 23, 38, .18), 0 6px 18px -8px rgba(14, 23, 38, .25); }
|
|
50
|
+
.fr-page-svg { display: block; width: 100%; height: 100%; }
|
|
51
|
+
.fr-page { position: relative; }
|
|
52
|
+
.fr-hit { position: absolute; background: rgba(242, 169, 0, .38); outline: 2px solid #f2a900; border-radius: 2px; pointer-events: none; }
|
|
53
|
+
.fr-search { display: inline-flex; align-items: center; gap: 4px; height: 30px; padding: 0 8px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); color: var(--fr-ink-2); background: var(--fr-panel); }
|
|
54
|
+
.fr-search input { width: 120px; border: 0; outline: none; font: inherit; color: var(--fr-ink); background: none; }
|
|
55
|
+
.fr-search:focus-within { border-color: var(--fr-accent); }
|
|
56
|
+
.fr-search-count { font-size: 12px; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
57
|
+
.fr-empty { margin: 48px auto; color: var(--fr-ink-2); }
|
|
58
|
+
.fr-overlay { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 10px; background: rgba(233, 236, 241, .72); font-weight: 600; color: var(--fr-ink-2); z-index: 5; }
|
|
59
|
+
.fr-overlay[hidden] { display: none; }
|
|
60
|
+
.fr-spinner { width: 18px; height: 18px; border: 2px solid var(--fr-rule); border-top-color: var(--fr-accent); border-radius: 50%; animation: fr-spin .8s linear infinite; }
|
|
61
|
+
@keyframes fr-spin { to { transform: rotate(360deg); } }
|
|
62
|
+
@media (prefers-reduced-motion: reduce) { .fr-spinner { animation-duration: 2.4s; } }
|
|
63
|
+
.fr-status { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 4px 10px; background: var(--fr-panel); border-top: 1px solid var(--fr-rule); color: var(--fr-ink-2); font-size: 12px; font-variant-numeric: tabular-nums; min-height: 26px; }
|
|
64
|
+
.fr-badge { color: var(--fr-ink-2); text-decoration: none; border: 1px solid var(--fr-rule); border-radius: 999px; padding: 0 8px; }
|
|
65
|
+
.fr-badge[hidden] { display: none; }
|
|
66
|
+
|
|
67
|
+
@media (max-width: 640px) {
|
|
68
|
+
.fr-btn span { display: none; }
|
|
69
|
+
.fr-btn { padding: 0 7px; }
|
|
70
|
+
.fr-pages { padding: 10px 8px 24px; }
|
|
71
|
+
}
|
|
72
|
+
@media print {
|
|
73
|
+
.fr-viewer .fr-toolbar, .fr-viewer .fr-status, .fr-viewer .fr-params { display: none; }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* ── Designer ─────────────────────────────────── */
|
|
77
|
+
.fr-designer { outline: none; }
|
|
78
|
+
.fr-designer .fr-toolbar { gap: 1px; }
|
|
79
|
+
.fr-designer .fr-group { display: inline-flex; align-items: center; gap: 1px; flex-wrap: wrap; }
|
|
80
|
+
.fr-designer.is-preview .fr-design-only, .fr-designer.is-json .fr-design-only { display: none; }
|
|
81
|
+
.fr-tabs { display: inline-flex; padding: 2px; background: var(--fr-bg); border-radius: 7px; }
|
|
82
|
+
.fr-tab { height: 26px; padding: 0 12px; border: 0; border-radius: 5px; background: none; font: inherit; font-weight: 600; color: var(--fr-ink-2); cursor: pointer; }
|
|
83
|
+
.fr-tab[aria-selected="true"] { background: var(--fr-panel); color: var(--fr-ink); box-shadow: 0 1px 2px rgba(14, 23, 38, .12); }
|
|
84
|
+
.fr-zoom-label { min-width: 42px; text-align: center; font-variant-numeric: tabular-nums; color: var(--fr-ink-2); }
|
|
85
|
+
.fr-dz { flex: 1; min-height: 0; display: grid; grid-template-columns: 200px minmax(0, 1fr) 270px; }
|
|
86
|
+
.fr-designer.is-preview .fr-dz, .fr-designer.is-json .fr-dz { grid-template-columns: minmax(0, 1fr); }
|
|
87
|
+
.fr-designer.is-preview .fr-dz-left, .fr-designer.is-preview .fr-dz-right, .fr-designer.is-json .fr-dz-left, .fr-designer.is-json .fr-dz-right { display: none; }
|
|
88
|
+
.fr-dz-left, .fr-dz-right { background: var(--fr-panel); overflow: auto; min-height: 0; }
|
|
89
|
+
.fr-dz-left { border-right: 1px solid var(--fr-rule); padding: 8px; }
|
|
90
|
+
.fr-dz-right { border-left: 1px solid var(--fr-rule); }
|
|
91
|
+
.fr-dz-left h3 { margin: 10px 4px 6px; font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--fr-ink-2); }
|
|
92
|
+
.fr-dz-left h3:first-child { margin-top: 2px; }
|
|
93
|
+
.fr-dz-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
|
|
94
|
+
.fr-dz-tool { display: flex; align-items: center; gap: 6px; padding: 6px; word-break: keep-all; overflow-wrap: anywhere; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); background: var(--fr-panel); font: inherit; font-size: 12px; color: var(--fr-ink); cursor: grab; text-align: left; }
|
|
95
|
+
.fr-dz-tool:hover, .fr-dz-field:hover { border-color: var(--fr-accent); color: var(--fr-accent); }
|
|
96
|
+
.fr-dz-fields { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
97
|
+
.fr-dz-field { padding: 3px 8px; border: 1px solid var(--fr-rule); border-radius: 999px; background: #f7f9fc; font: 12px/1.4 ui-monospace, Consolas, monospace; color: var(--fr-ink); cursor: grab; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
|
|
98
|
+
.fr-dz-empty { margin: 0 4px; color: var(--fr-ink-2); font-size: 12px; }
|
|
99
|
+
.fr-dz-bandopt { display: flex; align-items: center; gap: 6px; padding: 2px 4px; font-size: 12.5px; cursor: pointer; }
|
|
100
|
+
.fr-dz-groupopt { display: flex; align-items: center; justify-content: space-between; gap: 4px; padding: 2px 4px; font-size: 12px; }
|
|
101
|
+
.fr-dz-groupopt code { font-size: 11.5px; }
|
|
102
|
+
.fr-dz-addgroup { display: flex; gap: 4px; margin-top: 6px; }
|
|
103
|
+
.fr-dz-addgroup select { flex: 1; min-width: 0; height: 30px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); font: inherit; font-size: 12px; }
|
|
104
|
+
.fr-dz-addgroup .fr-btn span { font-size: 12px; }
|
|
105
|
+
.fr-dz-center { position: relative; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
|
|
106
|
+
.fr-dz-canvas { flex: 1; overflow: auto; padding: 24px 32px 64px; outline: none; }
|
|
107
|
+
.fr-dz-canvas[hidden], .fr-dz-preview[hidden], .fr-dz-json[hidden] { display: none; }
|
|
108
|
+
.fr-dz-page { margin: 0 auto; background: #fff; box-shadow: 0 1px 3px rgba(14, 23, 38, .16), 0 8px 24px -12px rgba(14, 23, 38, .3); user-select: none; }
|
|
109
|
+
.fr-dz-band { position: relative; }
|
|
110
|
+
.fr-dz-band-head { display: flex; justify-content: space-between; align-items: center; height: 20px; padding: 0 8px; background: #eef1f6; border-top: 1px solid var(--fr-rule); border-bottom: 1px solid var(--fr-rule); font-size: 11px; font-weight: 600; color: var(--fr-ink-2); cursor: pointer; }
|
|
111
|
+
.fr-dz-band-head small { font-weight: 500; font-variant-numeric: tabular-nums; }
|
|
112
|
+
.fr-dz-band.is-selected .fr-dz-band-head { background: #dfe6ff; color: var(--fr-accent); }
|
|
113
|
+
.fr-dz-band-area { position: relative; background-image: radial-gradient(circle, #d3d9e3 .8px, transparent .9px); overflow: visible; }
|
|
114
|
+
.fr-dz-band-resize { height: 5px; margin-top: -2px; position: relative; z-index: 3; cursor: ns-resize; }
|
|
115
|
+
.fr-dz-band-resize:hover { background: var(--fr-accent); opacity: .5; }
|
|
116
|
+
.fr-dz-hint { position: absolute; left: 8px; top: 50%; transform: translateY(-50%); color: #a6b0c0; font-size: 11px; pointer-events: none; white-space: nowrap; }
|
|
117
|
+
.fr-dz-el { position: absolute; cursor: move; outline: 1px dashed rgba(35, 64, 245, .18); }
|
|
118
|
+
.fr-dz-el:hover { outline-color: rgba(35, 64, 245, .55); }
|
|
119
|
+
.fr-dz-el.is-selected { outline: 1.5px solid var(--fr-accent); z-index: 2; }
|
|
120
|
+
.fr-dz-el.is-line { outline-offset: 2px; }
|
|
121
|
+
.fr-dz-el > * { pointer-events: none; }
|
|
122
|
+
.fr-dz-el > .fr-dz-h, .fr-dz-el > .fr-dz-inline { pointer-events: auto; }
|
|
123
|
+
.fr-dz-text { position: absolute; inset: 0; display: flex; flex-direction: column; overflow: hidden; white-space: pre-wrap; word-break: break-all; }
|
|
124
|
+
.fr-dz-text small { margin-left: 4px; font-size: 9px; color: #7a8599; font-weight: 400; }
|
|
125
|
+
.fr-dz-expr { color: #1a2fc0; }
|
|
126
|
+
.fr-dz-rect { position: absolute; inset: 0; }
|
|
127
|
+
.fr-dz-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
|
|
128
|
+
.fr-dz-el img { width: 100%; height: 100%; display: block; }
|
|
129
|
+
.fr-dz-ph { position: absolute; inset: 0; display: grid; place-items: center; background: repeating-linear-gradient(45deg, #f4f6fa, #f4f6fa 4px, #eceff5 4px, #eceff5 8px); color: #8a94a6; }
|
|
130
|
+
.fr-dz-h { position: absolute; width: 8px; height: 8px; background: #fff; border: 1.5px solid var(--fr-accent); border-radius: 2px; z-index: 3; }
|
|
131
|
+
.fr-dz-h-nw { left: -4px; top: -4px; cursor: nwse-resize; }
|
|
132
|
+
.fr-dz-h-n { left: calc(50% - 4px); top: -4px; cursor: ns-resize; }
|
|
133
|
+
.fr-dz-h-ne { right: -4px; top: -4px; cursor: nesw-resize; }
|
|
134
|
+
.fr-dz-h-e { right: -4px; top: calc(50% - 4px); cursor: ew-resize; }
|
|
135
|
+
.fr-dz-h-se { right: -4px; bottom: -4px; cursor: nwse-resize; }
|
|
136
|
+
.fr-dz-h-s { left: calc(50% - 4px); bottom: -4px; cursor: ns-resize; }
|
|
137
|
+
.fr-dz-h-sw { left: -4px; bottom: -4px; cursor: nesw-resize; }
|
|
138
|
+
.fr-dz-h-w { left: -4px; top: calc(50% - 4px); cursor: ew-resize; }
|
|
139
|
+
.fr-dz-marquee { position: absolute; border: 1px solid var(--fr-accent); background: rgba(35, 64, 245, .08); pointer-events: none; z-index: 4; }
|
|
140
|
+
.fr-dz-inline { position: absolute; inset: 0; min-height: 24px; z-index: 5; font: 13px/1.4 var(--fr-font); padding: 2px 4px; border: 2px solid var(--fr-accent); resize: none; }
|
|
141
|
+
.fr-dz-preview { flex: 1; min-height: 0; }
|
|
142
|
+
.fr-dz-preview .fr-viewer { border: 0; border-radius: 0; }
|
|
143
|
+
.fr-dz-json { flex: 1; min-height: 0; display: flex; flex-direction: column; }
|
|
144
|
+
.fr-dz-json textarea { flex: 1; border: 0; padding: 14px 16px; font: 12.5px/1.55 ui-monospace, "Cascadia Code", Consolas, monospace; resize: none; outline: none; background: #fbfcfe; color: var(--fr-ink); }
|
|
145
|
+
.fr-dz-json-bar { display: flex; justify-content: flex-end; align-items: center; gap: 12px; padding: 8px 12px; border-top: 1px solid var(--fr-rule); background: var(--fr-panel); }
|
|
146
|
+
.fr-dz-json-err { color: #c8102e; font-size: 12px; }
|
|
147
|
+
.fr-dz-props { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 4px 12px 24px; }
|
|
148
|
+
.fr-dz-sec { grid-column: 1 / -1; margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--fr-rule); font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--fr-ink-2); }
|
|
149
|
+
.fr-dz-sec:first-child { border-top: 0; margin-top: 4px; padding-top: 4px; }
|
|
150
|
+
.fr-dz-prop { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
|
|
151
|
+
.fr-dz-prop.is-wide { grid-column: 1 / -1; }
|
|
152
|
+
.fr-dz-prop.is-check { flex-direction: row; align-items: center; gap: 6px; grid-column: 1 / -1; font-size: 12.5px; cursor: pointer; }
|
|
153
|
+
.fr-dz-plabel { font-size: 11.5px; color: var(--fr-ink-2); font-weight: 600; }
|
|
154
|
+
.fr-dz-prop input[type=text], .fr-dz-prop input[type=number], .fr-dz-prop select, .fr-dz-prop textarea { width: 100%; height: 28px; padding: 0 7px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); font: inherit; font-size: 12.5px; color: var(--fr-ink); background: #fff; }
|
|
155
|
+
.fr-dz-prop textarea { height: auto; padding: 5px 7px; font-family: ui-monospace, Consolas, monospace; resize: vertical; }
|
|
156
|
+
.fr-dz-prop input.is-expr { font-family: ui-monospace, Consolas, monospace; }
|
|
157
|
+
.fr-dz-prop :focus-visible { outline: 2px solid var(--fr-accent); outline-offset: 0; }
|
|
158
|
+
.fr-dz-err { color: #c8102e; font-size: 11px; }
|
|
159
|
+
.fr-dz-err:empty { display: none; }
|
|
160
|
+
.fr-dz-color { display: flex; gap: 4px; }
|
|
161
|
+
.fr-dz-color input[type=color] { width: 30px; height: 28px; padding: 1px; border: 1px solid var(--fr-rule); border-radius: var(--fr-radius); background: #fff; flex: none; }
|
|
162
|
+
.fr-dz-toggles { display: flex; gap: 3px; flex-wrap: wrap; }
|
|
163
|
+
.fr-dz-toggle { width: 30px; height: 28px; padding: 0; justify-content: center; border: 1px solid var(--fr-rule); font-weight: 700; }
|
|
164
|
+
.fr-dz-toggle[aria-pressed="true"] { background: #dfe6ff; border-color: var(--fr-accent); color: var(--fr-accent); }
|
|
165
|
+
@media (max-width: 960px) {
|
|
166
|
+
.fr-dz { grid-template-columns: 150px minmax(0, 1fr); }
|
|
167
|
+
.fr-dz-right { display: none; }
|
|
168
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freereportjs/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "FreeReport — a web reporting engine (free for personal use): banded report designer, paged viewer, printing, PDF with embedded Korean fonts, Excel export.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|