@nice2dev/ui-printing 1.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +56 -0
  2. package/dist/index.cjs +2 -0
  3. package/dist/index.d.ts +15 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.mjs +3085 -0
  6. package/dist/print-button/NicePrintButton.d.ts +5 -0
  7. package/dist/print-button/NicePrintButton.d.ts.map +1 -0
  8. package/dist/print-button/index.d.ts +2 -0
  9. package/dist/print-button/index.d.ts.map +1 -0
  10. package/dist/print-preview/NicePrintPreview.d.ts +5 -0
  11. package/dist/print-preview/NicePrintPreview.d.ts.map +1 -0
  12. package/dist/print-preview/index.d.ts +2 -0
  13. package/dist/print-preview/index.d.ts.map +1 -0
  14. package/dist/print-queue/NicePrintQueue.d.ts +5 -0
  15. package/dist/print-queue/NicePrintQueue.d.ts.map +1 -0
  16. package/dist/print-queue/index.d.ts +2 -0
  17. package/dist/print-queue/index.d.ts.map +1 -0
  18. package/dist/style.css +1 -0
  19. package/dist/template-browser/NiceTemplateBrowser.d.ts +5 -0
  20. package/dist/template-browser/NiceTemplateBrowser.d.ts.map +1 -0
  21. package/dist/template-browser/index.d.ts +2 -0
  22. package/dist/template-browser/index.d.ts.map +1 -0
  23. package/dist/template-editor/NiceTemplateEditor.d.ts +6 -0
  24. package/dist/template-editor/NiceTemplateEditor.d.ts.map +1 -0
  25. package/dist/template-editor/index.d.ts +2 -0
  26. package/dist/template-editor/index.d.ts.map +1 -0
  27. package/dist/types/printingTypes.d.ts +249 -0
  28. package/dist/types/printingTypes.d.ts.map +1 -0
  29. package/package.json +66 -0
  30. package/src/globals.d.ts +9 -0
  31. package/src/index.ts +69 -0
  32. package/src/print-button/NicePrintButton.tsx +182 -0
  33. package/src/print-button/PrintButton.module.css +167 -0
  34. package/src/print-button/index.ts +1 -0
  35. package/src/print-preview/NicePrintPreview.tsx +417 -0
  36. package/src/print-preview/PrintPreview.module.css +122 -0
  37. package/src/print-preview/index.ts +1 -0
  38. package/src/print-queue/NicePrintQueue.tsx +350 -0
  39. package/src/print-queue/PrintQueue.module.css +203 -0
  40. package/src/print-queue/index.ts +1 -0
  41. package/src/template-browser/NiceTemplateBrowser.tsx +221 -0
  42. package/src/template-browser/TemplateBrowser.module.css +277 -0
  43. package/src/template-browser/index.ts +1 -0
  44. package/src/template-editor/NiceTemplateEditor.tsx +2386 -0
  45. package/src/template-editor/NiceTemplateEditor.tsx.first +1011 -0
  46. package/src/template-editor/NiceTemplateEditor.tsx.tmp +392 -0
  47. package/src/template-editor/TemplateEditor.module.css +1462 -0
  48. package/src/template-editor/index.ts +1 -0
  49. package/src/types/printingTypes.ts +301 -0
@@ -0,0 +1,182 @@
1
+ import React, { useState, useRef, useEffect, useCallback } from 'react';
2
+
3
+ import type { PrinterInfo as _PrinterInfo, PrintJobOptions, NicePrintButtonProps } from '../types/printingTypes';
4
+
5
+ import styles from './PrintButton.module.css';
6
+
7
+ export const NicePrintButton: React.FC<NicePrintButtonProps> = ({
8
+ onPrint,
9
+ printers = [],
10
+ defaultPrinterId,
11
+ defaultCopies = 1,
12
+ disabled = false,
13
+ loading = false,
14
+ variant = 'primary',
15
+ size = 'md',
16
+ label = 'Drukuj',
17
+ className,
18
+ style,
19
+ theme = 'light',
20
+ }) => {
21
+ const [open, setOpen] = useState(false);
22
+ const [copies, setCopies] = useState(defaultCopies);
23
+ const [printerId, setPrinterId] = useState(defaultPrinterId ?? printers[0]?.id ?? '');
24
+ const containerRef = useRef<HTMLDivElement>(null);
25
+
26
+ // Close on outside click
27
+ useEffect(() => {
28
+ if (!open) {
29
+ return;
30
+ }
31
+ const handler = (e: MouseEvent) => {
32
+ if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
33
+ setOpen(false);
34
+ }
35
+ };
36
+ document.addEventListener('mousedown', handler);
37
+ return () => document.removeEventListener('mousedown', handler);
38
+ }, [open]);
39
+
40
+ const handlePrint = useCallback(() => {
41
+ const options: PrintJobOptions = { copies, printerId };
42
+ onPrint(options);
43
+ setOpen(false);
44
+ }, [copies, printerId, onPrint]);
45
+
46
+ const increment = useCallback(() => setCopies((c) => Math.min(99, c + 1)), []);
47
+ const decrement = useCallback(() => setCopies((c) => Math.max(1, c - 1)), []);
48
+
49
+ const rootClass = [styles.container, theme === 'dark' ? styles.dark : '', className ?? '']
50
+ .filter(Boolean)
51
+ .join(' ');
52
+
53
+ const triggerClass = [
54
+ styles.trigger,
55
+ styles[`variant-${variant}`],
56
+ styles[`size-${size}`],
57
+ disabled || loading ? styles.triggerDisabled : '',
58
+ ]
59
+ .filter(Boolean)
60
+ .join(' ');
61
+
62
+ return (
63
+ <div ref={containerRef} className={rootClass} style={style}>
64
+ {/* Trigger button */}
65
+ <div className={styles.buttonGroup}>
66
+ <button
67
+ className={`${triggerClass} ${styles.mainAction}`}
68
+ disabled={disabled || loading}
69
+ onClick={handlePrint}
70
+ aria-label={label}
71
+ >
72
+ {loading ? <span className={styles.spinner} /> : <span>🖨</span>}
73
+ <span>{label}</span>
74
+ </button>
75
+ <button
76
+ className={`${triggerClass} ${styles.dropdownToggle}`}
77
+ disabled={disabled || loading}
78
+ onClick={() => setOpen((o) => !o)}
79
+ aria-label="Opcje druku"
80
+ aria-expanded={open}
81
+ >
82
+ <span className={`${styles.chevron} ${open ? styles.chevronUp : ''}`}>▾</span>
83
+ </button>
84
+ </div>
85
+
86
+ {/* Dropdown panel */}
87
+ {open && (
88
+ <div className={styles.dropdown}>
89
+ {/* Copies */}
90
+ <div className={styles.section}>
91
+ <label className={styles.sectionLabel}>Liczba kopii</label>
92
+ <div className={styles.copiesRow}>
93
+ <button className={styles.copiesBtn} onClick={decrement} disabled={copies <= 1}>
94
+
95
+ </button>
96
+ <span className={styles.copiesValue}>{copies}</span>
97
+ <button className={styles.copiesBtn} onClick={increment} disabled={copies >= 99}>
98
+ +
99
+ </button>
100
+ </div>
101
+ </div>
102
+
103
+ <div className={styles.divider} />
104
+
105
+ {/* Printer selection */}
106
+ {printers.length > 0 && (
107
+ <>
108
+ <div className={styles.section}>
109
+ <label className={styles.sectionLabel}>Drukarka</label>
110
+ <select
111
+ className={styles.printerSelect}
112
+ value={printerId}
113
+ onChange={(e) => setPrinterId(e.target.value)}
114
+ >
115
+ {printers.map((p) => (
116
+ <option
117
+ key={p.id}
118
+ value={p.id}
119
+ disabled={p.status === 'offline' || (!p.isOnline && p.status == null)}
120
+ >
121
+ {p.name}{' '}
122
+ {p.status === 'offline' || (!p.isOnline && p.status == null)
123
+ ? '(Offline)'
124
+ : p.status === 'busy'
125
+ ? '(Zajęta)'
126
+ : ''}
127
+ </option>
128
+ ))}
129
+ </select>
130
+ {/* Printer status indicator */}
131
+ {printers.find((p) => p.id === printerId) && (
132
+ <div className={styles.printerStatus}>
133
+ {(() => {
134
+ const p = printers.find((pr) => pr.id === printerId)!;
135
+ const s = p.status ?? (p.isOnline ? 'ready' : 'offline');
136
+ return (
137
+ <>
138
+ <span className={`${styles.printerDot} ${styles[`dot-${s}`]}`} />
139
+ <span className={styles.printerStatusLabel}>
140
+ {s === 'ready'
141
+ ? 'Gotowa'
142
+ : s === 'busy'
143
+ ? 'Zajęta'
144
+ : s === 'offline'
145
+ ? 'Offline'
146
+ : 'Błąd'}
147
+ </span>
148
+ </>
149
+ );
150
+ })()}
151
+ </div>
152
+ )}
153
+ </div>
154
+ <div className={styles.divider} />
155
+ </>
156
+ )}
157
+
158
+ {/* Submit */}
159
+ <div className={styles.section}>
160
+ <button
161
+ className={styles.submitBtn}
162
+ onClick={handlePrint}
163
+ disabled={
164
+ disabled ||
165
+ loading ||
166
+ (printers.length > 0 &&
167
+ (() => {
168
+ const p = printers.find((pr) => pr.id === printerId);
169
+ return (
170
+ p != null && (p.status === 'offline' || (!p.isOnline && p.status == null))
171
+ );
172
+ })())
173
+ }
174
+ >
175
+ {loading ? 'Drukowanie...' : `🖨 Drukuj${copies > 1 ? ` (${copies} kopie)` : ''}`}
176
+ </button>
177
+ </div>
178
+ </div>
179
+ )}
180
+ </div>
181
+ );
182
+ };
@@ -0,0 +1,167 @@
1
+ .container {
2
+ position: relative;
3
+ display: inline-flex;
4
+ flex-direction: column;
5
+ font-family: system-ui, sans-serif;
6
+ font-size: 14px;
7
+ }
8
+
9
+ /* Button group */
10
+ .buttonGroup {
11
+ display: flex;
12
+ align-items: stretch;
13
+ }
14
+
15
+ /* Base trigger */
16
+ .trigger {
17
+ display: inline-flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ gap: var(--nice-space-1-5, 6px);
21
+ border: none;
22
+ cursor: pointer;
23
+ font-weight: 500;
24
+ transition: background 0.15s, opacity 0.15s;
25
+ white-space: nowrap;
26
+ }
27
+ .triggerDisabled { opacity: 0.5; cursor: not-allowed; }
28
+
29
+ /* Variants */
30
+ .variant-primary { background: var(--nice-primary-hover, #2563eb); color: var(--nice-bg, #FFF); }
31
+ .variant-primary:not(.triggerDisabled):hover { background: var(--nice-primary-dark, #1d4ed8); }
32
+ .variant-secondary { background: var(--nice-bg-secondary, #f8fafc); color: var(--nice-text, #1e293b); border: 1px solid var(--nice-border, #e2e8f0); }
33
+ .variant-secondary:not(.triggerDisabled):hover { background: var(--nice-border, #e2e8f0); }
34
+ .variant-ghost { background: transparent; color: var(--nice-primary-hover, #2563eb); }
35
+ .variant-ghost:not(.triggerDisabled):hover { background: var(--nice-primary-bg, #eff6ff); }
36
+
37
+ /* Sizes */
38
+ .size-sm { padding: var(--nice-space-1-25, 5px) var(--nice-space-2-5, 10px); font-size: 12px; border-radius: var(--nice-radius-md, 6px) 0 0 var(--nice-radius-md, 6px); }
39
+ .size-md { padding: var(--nice-space-2, 8px) var(--nice-space-3-5, 14px); font-size: 14px; border-radius: var(--nice-radius-lg, 8px) 0 0 var(--nice-radius-lg, 8px); }
40
+ .size-lg { padding: var(--nice-space-2-5, 10px) 18px; font-size: 15px; border-radius: var(--nice-radius-lg, 10px) 0 0 var(--nice-radius-lg, 10px); }
41
+
42
+ /* Main action part */
43
+ .mainAction { flex: 1; border-right: 1px solid var(--nice-overlay-light-20, rgba(255, 255, 255, 0.2)); }
44
+ .variant-secondary .mainAction { border-right-color: var(--nice-border, #e2e8f0); }
45
+ .variant-ghost .mainAction { border-right-color: var(--nice-primary-bg, #dbeafe); }
46
+
47
+ /* Dropdown toggle */
48
+ .dropdownToggle {
49
+ padding: 0 var(--nice-space-2, 8px) !important;
50
+ }
51
+ .size-sm.dropdownToggle { border-radius: 0 var(--nice-radius-md, 6px) var(--nice-radius-md, 6px) 0; }
52
+ .size-md.dropdownToggle { border-radius: 0 var(--nice-radius-lg, 8px) var(--nice-radius-lg, 8px) 0; }
53
+ .size-lg.dropdownToggle { border-radius: 0 var(--nice-radius-lg, 10px) var(--nice-radius-lg, 10px) 0; }
54
+
55
+ .chevron { display: inline-block; transition: transform 0.2s; font-size: 12px; }
56
+ .chevronUp { transform: scaleY(-1); }
57
+
58
+ /* Dropdown panel */
59
+ .dropdown {
60
+ position: absolute;
61
+ top: calc(100% + 6px);
62
+ right: 0;
63
+ min-width: 220px;
64
+ background: var(--nice-bg, #FFF);
65
+ border: 1px solid var(--nice-border, #e2e8f0);
66
+ border-radius: var(--nice-radius-lg, 10px);
67
+ box-shadow: 0 8px 32px var(--nice-overlay-12, rgba(0, 0, 0, 0.12));
68
+ z-index: 1000;
69
+ overflow: hidden;
70
+ }
71
+ .dark .dropdown { background: var(--nice-text, #1e293b); border-color: var(--nice-text, #334155); box-shadow: 0 8px 32px var(--nice-overlay-50, rgba(0, 0, 0, 0.5)); }
72
+
73
+ .section { padding: var(--nice-space-3, 12px) var(--nice-space-3-5, 14px); }
74
+ .sectionLabel {
75
+ display: block;
76
+ font-size: 11px;
77
+ font-weight: 600;
78
+ text-transform: uppercase;
79
+ letter-spacing: 0.06em;
80
+ color: var(--nice-text-muted, #94a3b8);
81
+ margin-bottom: var(--nice-space-2, 8px);
82
+ }
83
+
84
+ .divider { height: 1px; background: var(--nice-bg-secondary, #f1f5f9); }
85
+ .dark .divider { background: var(--nice-text, #334155); }
86
+
87
+ /* Copies row */
88
+ .copiesRow {
89
+ display: flex;
90
+ align-items: center;
91
+ gap: var(--nice-space-2-5, 10px);
92
+ }
93
+ .copiesBtn {
94
+ width: 30px; height: 30px;
95
+ display: flex; align-items: center; justify-content: center;
96
+ background: var(--nice-bg-secondary, #f8fafc);
97
+ border: 1px solid var(--nice-border, #e2e8f0);
98
+ border-radius: var(--nice-radius-md, 6px);
99
+ cursor: pointer;
100
+ font-size: 16px;
101
+ color: var(--nice-text-secondary, #475569);
102
+ }
103
+ .copiesBtn:disabled { opacity: 0.4; cursor: default; }
104
+ .copiesBtn:not(:disabled):hover { background: var(--nice-border, #e2e8f0); }
105
+ .copiesValue {
106
+ flex: 1;
107
+ text-align: center;
108
+ font-size: 18px;
109
+ font-weight: 600;
110
+ color: var(--nice-text, #1e293b);
111
+ }
112
+ .dark .copiesValue { color: var(--nice-bg-secondary, #f1f5f9); }
113
+
114
+ /* Printer select */
115
+ .printerSelect {
116
+ width: 100%;
117
+ padding: var(--nice-space-1-75, 7px) var(--nice-space-2-5, 10px);
118
+ background: var(--nice-bg-secondary, #f8fafc);
119
+ border: 1px solid var(--nice-border, #e2e8f0);
120
+ border-radius: var(--nice-radius-md, 6px);
121
+ font-size: 13px;
122
+ color: var(--nice-text, #1e293b);
123
+ cursor: pointer;
124
+ }
125
+ .dark .printerSelect { background: var(--nice-text, #0f172a); border-color: var(--nice-text, #334155); color: var(--nice-bg-secondary, #f1f5f9); }
126
+ .printerSelect:focus { outline: none; border-color: var(--nice-primary-hover, #2563eb); }
127
+
128
+ .printerStatus {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: var(--nice-space-1-25, 5px);
132
+ margin-top: var(--nice-space-1-5, 6px);
133
+ font-size: 12px;
134
+ }
135
+ .printerDot { width: 7px; height: 7px; border-radius: var(--nice-radius-full, 50%); }
136
+ .dot-ready { background: var(--nice-success-dark, #16a34a); }
137
+ .dot-busy { background: var(--nice-warning, #f59e0b); }
138
+ .dot-offline { background: var(--nice-text-muted, #94a3b8); }
139
+ .dot-error { background: var(--nice-danger-dark, #dc2626); }
140
+ .printerStatusLabel { color: var(--nice-text-secondary, #64748b); }
141
+
142
+ /* Submit button */
143
+ .submitBtn {
144
+ width: 100%;
145
+ padding: 9px var(--nice-space-3-5, 14px);
146
+ background: var(--nice-primary-hover, #2563eb);
147
+ color: var(--nice-bg, #FFF);
148
+ border: none;
149
+ border-radius: var(--nice-radius-lg, 8px);
150
+ cursor: pointer;
151
+ font-size: 14px;
152
+ font-weight: 600;
153
+ text-align: center;
154
+ }
155
+ .submitBtn:hover:not(:disabled) { background: var(--nice-primary-dark, #1d4ed8); }
156
+ .submitBtn:disabled { opacity: 0.5; cursor: not-allowed; }
157
+
158
+ /* Spinner */
159
+ .spinner {
160
+ display: inline-block;
161
+ width: 14px; height: 14px;
162
+ border: 2px solid var(--nice-overlay-light-30, rgba(255, 255, 255, 0.3));
163
+ border-top-color: var(--nice-bg, #FFF);
164
+ border-radius: var(--nice-radius-full, 50%);
165
+ animation: spin 0.7s linear infinite;
166
+ }
167
+ @keyframes spin { to { transform: rotate(360deg); } }
@@ -0,0 +1 @@
1
+ export { NicePrintButton } from './NicePrintButton';