cozy-ui 135.5.0 → 135.6.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/CHANGELOG.md +7 -0
- package/assets/icons/ui/expand.svg +1 -0
- package/assets/icons/ui/export.svg +1 -0
- package/assets/icons/ui/narrow.svg +1 -0
- package/package.json +1 -1
- package/react/ActionsMenu/Actions/exportToText.js +54 -0
- package/react/ActionsMenu/Actions/helpers.js +20 -0
- package/react/ActionsMenu/Actions/index.js +1 -0
- package/react/ActionsMenu/Actions/locales/en.json +2 -1
- package/react/ActionsMenu/Actions/locales/fr.json +2 -1
- package/react/ActionsMenu/Actions/locales/ru.json +3 -2
- package/react/ActionsMenu/Actions/locales/vi.json +3 -2
- package/react/ActionsMenu/Actions/pdfHelpers.js +187 -0
- package/react/Icon/Readme.md +7 -1
- package/react/Icons/Expand.jsx +12 -0
- package/react/Icons/Export.jsx +13 -0
- package/react/Icons/Narrow.jsx +16 -0
- package/transpiled/react/ActionsMenu/Actions/exportToText.d.ts +13 -0
- package/transpiled/react/ActionsMenu/Actions/exportToText.js +84 -0
- package/transpiled/react/ActionsMenu/Actions/helpers.d.ts +1 -0
- package/transpiled/react/ActionsMenu/Actions/helpers.js +20 -1
- package/transpiled/react/ActionsMenu/Actions/index.d.ts +1 -0
- package/transpiled/react/ActionsMenu/Actions/index.js +2 -1
- package/transpiled/react/ActionsMenu/Actions/locales/withActionsLocales.js +8 -4
- package/transpiled/react/ActionsMenu/Actions/pdfHelpers.d.ts +34 -0
- package/transpiled/react/ActionsMenu/Actions/pdfHelpers.js +242 -0
- package/transpiled/react/Icon/icons-sprite.d.ts +1 -1
- package/transpiled/react/Icon/icons-sprite.js +1 -1
- package/transpiled/react/Icons/Expand.d.ts +2 -0
- package/transpiled/react/Icons/Expand.js +14 -0
- package/transpiled/react/Icons/Export.d.ts +2 -0
- package/transpiled/react/Icons/Export.js +16 -0
- package/transpiled/react/Icons/Narrow.d.ts +2 -0
- package/transpiled/react/Icons/Narrow.js +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [135.6.0](https://github.com/cozy/cozy-ui/compare/v135.5.0...v135.6.0) (2026-01-27)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Implement new actions ExportToText and new icons :sparkles: ([6714f4a](https://github.com/cozy/cozy-ui/commit/6714f4a))
|
|
7
|
+
|
|
1
8
|
# [135.5.0](https://github.com/cozy/cozy-ui/compare/v135.4.0...v135.5.0) (2026-01-24)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.8 15.2a.8.8 0 0 0-.8-.8H2.8a.8.8 0 0 0 0 1.6H14a.8.8 0 0 0 .8-.8ZM14.8.8A.8.8 0 0 0 14 0H2.8a.8.8 0 1 0 0 1.6H14a.8.8 0 0 0 .8-.8ZM6.893 9.833a.799.799 0 0 0-1.128 1.132l1.928 1.928a1 1 0 0 0 1.414 0l1.928-1.928a.799.799 0 0 0-1.128-1.132l-.707.703V5.464l.707.703a.799.799 0 0 0 1.128-1.132L9.107 3.107a1 1 0 0 0-1.414 0L5.765 5.035a.799.799 0 0 0 1.128 1.132l.707-.703v5.072l-.707-.703Z" fill="#2C3038"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.8 4v10.4l-.008.159A1.6 1.6 0 0 1 13.2 16H3.6a1.6 1.6 0 0 1-1.014-.362l-.117-.107a1.6 1.6 0 0 1-.461-.972L2 14.4V1.6c0-.372.13-.73.362-1.014L2.47.469A1.6 1.6 0 0 1 3.599 0h7.2l4 4ZM3.6 14.4h9.6V5.6h-1.598a2.4 2.4 0 0 1-2.4-2.4V1.6H3.6v12.8Zm7.202-11.2a.8.8 0 0 0 .8.8h.935l-1.736-1.736V3.2Z" fill="#2C3038"/><path d="M8.401 7.2a.8.8 0 0 1 .8.799v2.867l1.034-1.032a.8.8 0 1 1 1.131 1.13l-2.4 2.401a.794.794 0 0 1-.436.222.817.817 0 0 1-.13.013.793.793 0 0 1-.127-.013.794.794 0 0 1-.438-.222l-2.4-2.4a.8.8 0 1 1 1.131-1.131l1.035 1.034V8a.8.8 0 0 1 .8-.8Z" fill="#2C3038"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M15.736.264a.9.9 0 0 1 0 1.274L12.07 5.204h2.027a.9.9 0 1 1 0 1.802H9.896a.9.9 0 0 1-.901-.9V1.901a.9.9 0 1 1 1.802 0V3.93L14.462.264a.9.9 0 0 1 1.274 0ZM1 9.895a.9.9 0 0 1 .902-.901h4.203a.9.9 0 0 1 .901.9v4.204a.9.9 0 0 1-1.802 0V12.07l-3.666 3.667a.9.9 0 0 1-1.274-1.274l3.667-3.666H1.9a.9.9 0 0 1-.9-.901Z" fill="#2C3038"/></svg>
|
package/package.json
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import logger from 'cozy-logger'
|
|
4
|
+
|
|
5
|
+
import { downloadBlob } from './helpers'
|
|
6
|
+
import { getActionsI18n } from './locales/withActionsLocales'
|
|
7
|
+
import { makePdfBlobFromText } from './pdfHelpers'
|
|
8
|
+
import Icon from '../../Icon'
|
|
9
|
+
import ExportIcon from '../../Icons/Export'
|
|
10
|
+
import ListItemIcon from '../../ListItemIcon'
|
|
11
|
+
import ListItemText from '../../ListItemText'
|
|
12
|
+
import ActionsMenuItem from '../ActionsMenuItem'
|
|
13
|
+
|
|
14
|
+
const makeComponent = (label, icon) => {
|
|
15
|
+
const Component = forwardRef((props, ref) => {
|
|
16
|
+
return (
|
|
17
|
+
<ActionsMenuItem {...props} ref={ref}>
|
|
18
|
+
<ListItemIcon>
|
|
19
|
+
<Icon icon={icon} />
|
|
20
|
+
</ListItemIcon>
|
|
21
|
+
<ListItemText primary={label} />
|
|
22
|
+
</ActionsMenuItem>
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
Component.displayName = 'exportToText'
|
|
27
|
+
|
|
28
|
+
return Component
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const exportToText = ({ exportedText, file }) => {
|
|
32
|
+
const { t } = getActionsI18n()
|
|
33
|
+
const icon = ExportIcon
|
|
34
|
+
const label = t('exportToText')
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
name: 'exportToText',
|
|
38
|
+
icon,
|
|
39
|
+
label,
|
|
40
|
+
displayCondition: () => !!exportedText,
|
|
41
|
+
Component: makeComponent(label, icon),
|
|
42
|
+
action: async () => {
|
|
43
|
+
try {
|
|
44
|
+
const blob = await makePdfBlobFromText(exportedText)
|
|
45
|
+
const baseName = file?.name
|
|
46
|
+
? `${file.name.replace(/\.[^/.]+$/, '')}_export`
|
|
47
|
+
: 'export'
|
|
48
|
+
downloadBlob(blob, `${baseName}.pdf`)
|
|
49
|
+
} catch (error) {
|
|
50
|
+
logger.error(error)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -238,3 +238,23 @@ export const makePdfBlob = async ({ client, docs, fetchBlobFileById }) => {
|
|
|
238
238
|
|
|
239
239
|
return blob
|
|
240
240
|
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Trigger a browser download for a given blob.
|
|
244
|
+
*
|
|
245
|
+
* @param {Blob} blob - File content
|
|
246
|
+
* @param {string} filename - Desired filename
|
|
247
|
+
* @returns {void}
|
|
248
|
+
*/
|
|
249
|
+
export const downloadBlob = (blob, filename) => {
|
|
250
|
+
if (!blob || !filename) return
|
|
251
|
+
|
|
252
|
+
const url = URL.createObjectURL(blob)
|
|
253
|
+
const a = document.createElement('a')
|
|
254
|
+
a.href = url
|
|
255
|
+
a.download = filename
|
|
256
|
+
a.style.display = 'none'
|
|
257
|
+
document.body.appendChild(a)
|
|
258
|
+
a.click()
|
|
259
|
+
a.remove()
|
|
260
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { PDFDocument, StandardFonts } from 'pdf-lib'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wrap a string into multiple lines based on available width.
|
|
5
|
+
*
|
|
6
|
+
* @param {object} opts
|
|
7
|
+
* @param {import('pdf-lib').PDFFont} opts.font - Embedded pdf-lib font
|
|
8
|
+
* @param {number} opts.fontSize - Font size
|
|
9
|
+
* @param {number} opts.maxLineWidth - Max line width in PDF units
|
|
10
|
+
* @param {string} opts.line - Text to wrap
|
|
11
|
+
* @returns {string[]} Wrapped lines
|
|
12
|
+
*/
|
|
13
|
+
export const wrapTextToLines = ({ font, fontSize, maxLineWidth, line }) => {
|
|
14
|
+
if (!line) return []
|
|
15
|
+
if (fontSize <= 0 || maxLineWidth <= 0) return [line]
|
|
16
|
+
|
|
17
|
+
const words = line.split(' ')
|
|
18
|
+
|
|
19
|
+
return words.reduce((lines, word) => {
|
|
20
|
+
const currentLine = lines[lines.length - 1]
|
|
21
|
+
|
|
22
|
+
if (!currentLine) {
|
|
23
|
+
return [word]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const testLine = `${currentLine} ${word}`
|
|
27
|
+
const testWidth = font.widthOfTextAtSize(testLine, fontSize)
|
|
28
|
+
|
|
29
|
+
if (testWidth <= maxLineWidth) {
|
|
30
|
+
lines[lines.length - 1] = testLine
|
|
31
|
+
} else {
|
|
32
|
+
lines.push(word)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return lines
|
|
36
|
+
}, [])
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Add a new page if there is not enough space to draw a new line.
|
|
41
|
+
*
|
|
42
|
+
* @param {object} opts
|
|
43
|
+
* @param {PDFDocument} opts.pdfDoc - pdf-lib document
|
|
44
|
+
* @param {import('pdf-lib').PDFPage} opts.page - Current page
|
|
45
|
+
* @param {number} opts.y - Current y cursor position
|
|
46
|
+
* @param {number} opts.requiredHeight - Height required before adding a new page
|
|
47
|
+
* @param {number} opts.marginTop - Top margin
|
|
48
|
+
* @param {number} opts.marginBottom - Bottom margin
|
|
49
|
+
* @returns {{ page: import('pdf-lib').PDFPage, y: number }} Updated page and y
|
|
50
|
+
*/
|
|
51
|
+
export const pushNewPageIfNeeded = ({
|
|
52
|
+
pdfDoc,
|
|
53
|
+
page,
|
|
54
|
+
y,
|
|
55
|
+
requiredHeight,
|
|
56
|
+
marginTop,
|
|
57
|
+
marginBottom
|
|
58
|
+
}) => {
|
|
59
|
+
if (!pdfDoc || !page) {
|
|
60
|
+
throw new Error('pdfDoc and page are required')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { width, height } = page.getSize()
|
|
64
|
+
|
|
65
|
+
if (y - requiredHeight < marginBottom) {
|
|
66
|
+
const newPage = pdfDoc.addPage([width, height])
|
|
67
|
+
return {
|
|
68
|
+
page: newPage,
|
|
69
|
+
y: height - marginTop
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { page, y }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Draws a plain text string onto a PDF, wrapping lines to max width and handling page breaks.
|
|
78
|
+
*
|
|
79
|
+
* @param {object} opts
|
|
80
|
+
* @param {PDFDocument} opts.pdfDoc - pdf-lib document
|
|
81
|
+
* @param {import('pdf-lib').PDFPage} opts.page - Current page
|
|
82
|
+
* @param {number} opts.y - Current y cursor position
|
|
83
|
+
* @param {string} opts.text - Text to draw
|
|
84
|
+
* @param {import('pdf-lib').PDFFont} opts.font - Embedded pdf-lib font
|
|
85
|
+
* @param {number} opts.fontSize - Font size
|
|
86
|
+
* @param {number} opts.lineHeight - Line height
|
|
87
|
+
* @param {number} opts.marginX - Left margin
|
|
88
|
+
* @param {number} opts.marginY - Top/bottom margin
|
|
89
|
+
* @param {number} opts.maxLineWidth - Max line width in PDF units
|
|
90
|
+
* @returns {{ page: import('pdf-lib').PDFPage, y: number }} Updated page and y
|
|
91
|
+
*/
|
|
92
|
+
export const drawWrappedText = ({
|
|
93
|
+
pdfDoc,
|
|
94
|
+
page,
|
|
95
|
+
y,
|
|
96
|
+
text,
|
|
97
|
+
font,
|
|
98
|
+
fontSize,
|
|
99
|
+
lineHeight,
|
|
100
|
+
marginX,
|
|
101
|
+
marginY,
|
|
102
|
+
maxLineWidth
|
|
103
|
+
}) => {
|
|
104
|
+
let currentPage = page
|
|
105
|
+
let currentY = y
|
|
106
|
+
|
|
107
|
+
const paragraphs = String(text ?? '').split(/\r?\n/)
|
|
108
|
+
|
|
109
|
+
const renderItems = paragraphs.flatMap(paragraph => {
|
|
110
|
+
const wrappedLines = wrapTextToLines({
|
|
111
|
+
font,
|
|
112
|
+
fontSize,
|
|
113
|
+
maxLineWidth,
|
|
114
|
+
line: paragraph
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return [...wrappedLines, { type: 'paragraphGap' }]
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
for (const item of renderItems) {
|
|
121
|
+
if (typeof item === 'object' && item.type === 'paragraphGap') {
|
|
122
|
+
currentY -= lineHeight / 2
|
|
123
|
+
continue
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const nextState = pushNewPageIfNeeded({
|
|
127
|
+
pdfDoc,
|
|
128
|
+
page: currentPage,
|
|
129
|
+
y: currentY,
|
|
130
|
+
requiredHeight: lineHeight,
|
|
131
|
+
marginTop: marginY,
|
|
132
|
+
marginBottom: marginY
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
currentPage = nextState.page
|
|
136
|
+
currentY = nextState.y
|
|
137
|
+
|
|
138
|
+
currentPage.drawText(item, {
|
|
139
|
+
x: marginX,
|
|
140
|
+
y: currentY - fontSize,
|
|
141
|
+
size: fontSize,
|
|
142
|
+
font
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
currentY -= lineHeight
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { page: currentPage, y: currentY }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Creates a PDF Blob from a plain text string.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} text - Text content to put into the PDF
|
|
155
|
+
* @returns {Promise<Blob>} PDF file as a Blob
|
|
156
|
+
*/
|
|
157
|
+
export const makePdfBlobFromText = async text => {
|
|
158
|
+
const pdfDoc = await PDFDocument.create()
|
|
159
|
+
const font = await pdfDoc.embedFont(StandardFonts.Helvetica)
|
|
160
|
+
|
|
161
|
+
const CONFIG = {
|
|
162
|
+
fontSize: 12,
|
|
163
|
+
lineHeight: 16,
|
|
164
|
+
marginX: 40,
|
|
165
|
+
marginY: 40,
|
|
166
|
+
pageSize: [595.28, 841.89] // A4
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const maxLineWidth = CONFIG.pageSize[0] - CONFIG.marginX * 2
|
|
170
|
+
const initialPage = pdfDoc.addPage(CONFIG.pageSize)
|
|
171
|
+
|
|
172
|
+
drawWrappedText({
|
|
173
|
+
pdfDoc,
|
|
174
|
+
page: initialPage,
|
|
175
|
+
y: CONFIG.pageSize[1] - CONFIG.marginY,
|
|
176
|
+
text,
|
|
177
|
+
font,
|
|
178
|
+
fontSize: CONFIG.fontSize,
|
|
179
|
+
lineHeight: CONFIG.lineHeight,
|
|
180
|
+
marginX: CONFIG.marginX,
|
|
181
|
+
marginY: CONFIG.marginY,
|
|
182
|
+
maxLineWidth
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const pdfBytes = await pdfDoc.save()
|
|
186
|
+
return new Blob([pdfBytes], { type: 'application/pdf' })
|
|
187
|
+
}
|
package/react/Icon/Readme.md
CHANGED
|
@@ -170,7 +170,9 @@ import EmailOpen from 'cozy-ui/transpiled/react/Icons/EmailOpen'
|
|
|
170
170
|
import Eu from 'cozy-ui/transpiled/react/Icons/Eu'
|
|
171
171
|
import Euro from 'cozy-ui/transpiled/react/Icons/Euro'
|
|
172
172
|
import Exchange from 'cozy-ui/transpiled/react/Icons/Exchange'
|
|
173
|
+
import Expand from 'cozy-ui/transpiled/react/Icons/Expand'
|
|
173
174
|
import Expert from 'cozy-ui/transpiled/react/Icons/Expert'
|
|
175
|
+
import Export from 'cozy-ui/transpiled/react/Icons/Export'
|
|
174
176
|
import Eye from 'cozy-ui/transpiled/react/Icons/Eye'
|
|
175
177
|
import EyeClosed from 'cozy-ui/transpiled/react/Icons/EyeClosed'
|
|
176
178
|
import FaceId from 'cozy-ui/transpiled/react/Icons/FaceId'
|
|
@@ -245,6 +247,7 @@ import MovementOut from 'cozy-ui/transpiled/react/Icons/MovementOut'
|
|
|
245
247
|
import Moveto from 'cozy-ui/transpiled/react/Icons/Moveto'
|
|
246
248
|
import MultiFiles from 'cozy-ui/transpiled/react/Icons/MultiFiles'
|
|
247
249
|
import Music from 'cozy-ui/transpiled/react/Icons/Music'
|
|
250
|
+
import Narrow from 'cozy-ui/transpiled/react/Icons/Narrow'
|
|
248
251
|
import New from 'cozy-ui/transpiled/react/Icons/New'
|
|
249
252
|
import Next from 'cozy-ui/transpiled/react/Icons/Next'
|
|
250
253
|
import Note from 'cozy-ui/transpiled/react/Icons/Note'
|
|
@@ -461,7 +464,9 @@ const icons = [
|
|
|
461
464
|
Eu,
|
|
462
465
|
Euro,
|
|
463
466
|
Exchange,
|
|
467
|
+
Expand,
|
|
464
468
|
Expert,
|
|
469
|
+
Export,
|
|
465
470
|
Eye,
|
|
466
471
|
EyeClosed,
|
|
467
472
|
FaceId,
|
|
@@ -536,6 +541,7 @@ const icons = [
|
|
|
536
541
|
Moveto,
|
|
537
542
|
MultiFiles,
|
|
538
543
|
Music,
|
|
544
|
+
Narrow,
|
|
539
545
|
New,
|
|
540
546
|
Next,
|
|
541
547
|
Note,
|
|
@@ -1014,7 +1020,7 @@ import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
|
1014
1020
|
|
|
1015
1021
|
const colors = ['#297EF2', '#08b442', '#B449E7', '#F52D2D', '#FF962F']
|
|
1016
1022
|
let i = 0
|
|
1017
|
-
const availableIcons = ['album-add','album-remove','album','answer','apple','archive','arrowUp', 'article', 'assign-admin','assign-moderator','attachment','attention','bank-check','bank','banking-add','banking','bell','benefit','bike','bill','bottom','browser-brave','browser-chrome','browser-duckduckgo','browser-edge','browser-edge-chromium','browser-firefox','browser-ie','browser-opera','browser-safari','burger','bus','calendar','camera','car','carbonCopy','carpooling','categories','certified','check-circle','check-list','check-square','check','checkbox','chess','child','circle-filled','clock','clock-outline','cloud-happy','cloud-rainbow','cloud-plus-outlined','cloud','cloud2','collect','cocktail','comment','company','compare','compass','connector','contract','contrast','copy','cozy-circle','cozy-laugh', 'cozy-lock', 'cozy-text', 'cozy-release', 'credit-card-add','credit-card','credit','crop','cross-circle-outline','cross-circle','cross-medium','cross-small','cross','cube','dash','dashboard','data-control','database','debit','desktop-download','devices','discuss','dots','down','download','drawing-arrow-up','dropdown-close','dropdown-open','dropdown','dropup','electric-bike','electric-car','electric-scooter','email-notification','email-open','email','eu','euro','exchange','expert','eye-closed','eye','face-id','file-add','file-duotone','file-new','file-none','file-outline','file','filter','fingerprint','fitness','flag-outlined','flag','flash-auto','flashlight','folder-add','folder-moveto','folder-open','folder','forbidden','from-user','gear','globe','gouv','graph-circle','grid','group-list','groups','growth','hand','heart','help','help-outlined','history','home','hourglass','image','info-outlined','info','justice','key','key2','label-outlined','laudry','laptop','left','library','lightbulb','lightning','link-out','link','list','list-min','location','lock', 'lock-screen', 'logout','magic-trick','magnet','magnifier','matrix','merge','moped','mosaic','mosaic-min','motorcycle','mountain','movement-in','movement-out','mouvement','moveto','multi-files','music','new','next','note','notification-email','number','offline','online', 'openapp', 'openwith','palette','paper','paperplane','password','pen','people','peoples','percent-circle','percent','person-add','personal-data','phone-download','phone-upload','phone','pie-chart','pin','plane','planet','plus-small','plus', 'pop-inside', 'previous','printer','qualify','radio-checked','radio-unchecked','refresh','relationship','remboursement','rename','repare','reply','restaurant','restore-straight','restore','right','rise','rotate-left','rotate-right','sad-cozy','safe','school','scooter','secutiry','select-all','send','server','setting','share-circle','share','shield','shield-infected','shield-clean','shop','sound','spinner','sport-bag','stack','star','star-outline','stats','stop', 'subway', 'support', 'swap', 'sync-cozy','sync','tab','tag','target','task','team','telecom','telephone','text','text-info','to-the-cloud','top','train','tram','trash','trophy', 'uncloud', 'unknow','unlink','unlock','up','upload','videos','walk','wallet-add','wallet-new','wallet','warn','warning-circle','warning','water','wrench-circle','work']
|
|
1023
|
+
const availableIcons = ['album-add','album-remove','album','answer','apple','archive','arrowUp', 'article', 'assign-admin','assign-moderator','attachment','attention','bank-check','bank','banking-add','banking','bell','benefit','bike','bill','bottom','browser-brave','browser-chrome','browser-duckduckgo','browser-edge','browser-edge-chromium','browser-firefox','browser-ie','browser-opera','browser-safari','burger','bus','calendar','camera','car','carbonCopy','carpooling','categories','certified','check-circle','check-list','check-square','check','checkbox','chess','child','circle-filled','clock','clock-outline','cloud-happy','cloud-rainbow','cloud-plus-outlined','cloud','cloud2','collect','cocktail','comment','company','compare','compass','connector','contract','contrast','copy','cozy-circle','cozy-laugh', 'cozy-lock', 'cozy-text', 'cozy-release', 'credit-card-add','credit-card','credit','crop','cross-circle-outline','cross-circle','cross-medium','cross-small','cross','cube','dash','dashboard','data-control','database','debit','desktop-download','devices','discuss','dots','down','download','drawing-arrow-up','dropdown-close','dropdown-open','dropdown','dropup','electric-bike','electric-car','electric-scooter','email-notification','email-open','email','eu','euro','exchange','expand','expert','export','eye-closed','eye','face-id','file-add','file-duotone','file-new','file-none','file-outline','file','filter','fingerprint','fitness','flag-outlined','flag','flash-auto','flashlight','folder-add','folder-moveto','folder-open','folder','forbidden','from-user','gear','globe','gouv','graph-circle','grid','group-list','groups','growth','hand','heart','help','help-outlined','history','home','hourglass','image','info-outlined','info','justice','key','key2','label-outlined','laudry','laptop','left','library','lightbulb','lightning','link-out','link','list','list-min','location','lock', 'lock-screen', 'logout','magic-trick','magnet','magnifier','matrix','merge','moped','mosaic','mosaic-min','motorcycle','mountain','movement-in','movement-out','mouvement','moveto','multi-files','music','narrow','new','next','note','notification-email','number','offline','online', 'openapp', 'openwith','palette','paper','paperplane','password','pen','people','peoples','percent-circle','percent','person-add','personal-data','phone-download','phone-upload','phone','pie-chart','pin','plane','planet','plus-small','plus', 'pop-inside', 'previous','printer','qualify','radio-checked','radio-unchecked','refresh','relationship','remboursement','rename','repare','reply','restaurant','restore-straight','restore','right','rise','rotate-left','rotate-right','sad-cozy','safe','school','scooter','secutiry','select-all','send','server','setting','share-circle','share','shield','shield-infected','shield-clean','shop','sound','spinner','sport-bag','stack','star','star-outline','stats','stop', 'subway', 'support', 'swap', 'sync-cozy','sync','tab','tag','target','task','team','telecom','telephone','text','text-info','to-the-cloud','top','train','tram','trash','trophy', 'uncloud', 'unknow','unlink','unlock','up','upload','videos','walk','wallet-add','wallet-new','wallet','warn','warning-circle','warning','water','wrench-circle','work']
|
|
1018
1024
|
;
|
|
1019
1025
|
|
|
1020
1026
|
<Grid container spacing={2}>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Automatically created, please run `scripts/generate-svgr-icon.sh assets/icons/ui/expand.svg` to regenerate;
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
function SvgExpand(props) {
|
|
5
|
+
return (
|
|
6
|
+
<svg viewBox="0 0 16 16" fill="none" {...props}>
|
|
7
|
+
<path d="M14.8 15.2a.8.8 0 00-.8-.8H2.8a.8.8 0 000 1.6H14a.8.8 0 00.8-.8zm0-14.4A.8.8 0 0014 0H2.8a.8.8 0 100 1.6H14a.8.8 0 00.8-.8zM6.893 9.833a.799.799 0 00-1.128 1.132l1.928 1.928a1 1 0 001.414 0l1.928-1.928a.799.799 0 00-1.128-1.132l-.707.703V5.464l.707.703a.799.799 0 001.128-1.132L9.107 3.107a1 1 0 00-1.414 0L5.765 5.035a.799.799 0 001.128 1.132l.707-.703v5.072l-.707-.703z" />
|
|
8
|
+
</svg>
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default SvgExpand
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Automatically created, please run `scripts/generate-svgr-icon.sh assets/icons/ui/export.svg` to regenerate;
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
function SvgExport(props) {
|
|
5
|
+
return (
|
|
6
|
+
<svg viewBox="0 0 16 16" fill="none" {...props}>
|
|
7
|
+
<path d="M14.8 4v10.4l-.008.159A1.6 1.6 0 0113.2 16H3.6a1.6 1.6 0 01-1.014-.362l-.117-.107a1.6 1.6 0 01-.461-.972L2 14.4V1.6c0-.372.13-.73.362-1.014L2.47.469A1.6 1.6 0 013.599 0h7.2l4 4zM3.6 14.4h9.6V5.6h-1.598a2.4 2.4 0 01-2.4-2.4V1.6H3.6v12.8zm7.202-11.2a.8.8 0 00.8.8h.935l-1.736-1.736V3.2z" />
|
|
8
|
+
<path d="M8.401 7.2a.8.8 0 01.8.799v2.867l1.034-1.032a.8.8 0 111.131 1.13l-2.4 2.401a.794.794 0 01-.436.222.817.817 0 01-.13.013.793.793 0 01-.127-.013.794.794 0 01-.438-.222l-2.4-2.4a.8.8 0 111.131-1.131l1.035 1.034V8a.8.8 0 01.8-.8z" />
|
|
9
|
+
</svg>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default SvgExport
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Automatically created, please run `scripts/generate-svgr-icon.sh assets/icons/ui/narrow.svg` to regenerate;
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
function SvgNarrow(props) {
|
|
5
|
+
return (
|
|
6
|
+
<svg viewBox="0 0 16 16" fill="none" {...props}>
|
|
7
|
+
<path
|
|
8
|
+
fillRule="evenodd"
|
|
9
|
+
clipRule="evenodd"
|
|
10
|
+
d="M15.736.264a.9.9 0 010 1.274L12.07 5.204h2.027a.9.9 0 110 1.802H9.896a.9.9 0 01-.901-.9V1.901a.9.9 0 111.802 0V3.93L14.462.264a.9.9 0 011.274 0zM1 9.895a.9.9 0 01.902-.901h4.203a.9.9 0 01.901.9v4.204a.9.9 0 01-1.802 0V12.07l-3.666 3.667a.9.9 0 01-1.274-1.274l3.667-3.666H1.9a.9.9 0 01-.9-.901z"
|
|
11
|
+
/>
|
|
12
|
+
</svg>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default SvgNarrow
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function exportToText({ exportedText, file }: {
|
|
2
|
+
exportedText: any;
|
|
3
|
+
file: any;
|
|
4
|
+
}): {
|
|
5
|
+
name: string;
|
|
6
|
+
icon: typeof ExportIcon;
|
|
7
|
+
label: any;
|
|
8
|
+
displayCondition: () => boolean;
|
|
9
|
+
Component: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
|
|
10
|
+
action: () => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
import ExportIcon from "../../Icons/Export";
|
|
13
|
+
import React from "react";
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
3
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
4
|
+
import React, { forwardRef } from 'react';
|
|
5
|
+
import logger from 'cozy-logger';
|
|
6
|
+
import { downloadBlob } from "cozy-ui/transpiled/react/ActionsMenu/Actions/helpers";
|
|
7
|
+
import { getActionsI18n } from "cozy-ui/transpiled/react/ActionsMenu/Actions/locales/withActionsLocales";
|
|
8
|
+
import { makePdfBlobFromText } from "cozy-ui/transpiled/react/ActionsMenu/Actions/pdfHelpers";
|
|
9
|
+
import Icon from "cozy-ui/transpiled/react/Icon";
|
|
10
|
+
import ExportIcon from "cozy-ui/transpiled/react/Icons/Export";
|
|
11
|
+
import ListItemIcon from "cozy-ui/transpiled/react/ListItemIcon";
|
|
12
|
+
import ListItemText from "cozy-ui/transpiled/react/ListItemText";
|
|
13
|
+
import ActionsMenuItem from "cozy-ui/transpiled/react/ActionsMenu/ActionsMenuItem";
|
|
14
|
+
|
|
15
|
+
var makeComponent = function makeComponent(label, icon) {
|
|
16
|
+
var Component = /*#__PURE__*/forwardRef(function (props, ref) {
|
|
17
|
+
return /*#__PURE__*/React.createElement(ActionsMenuItem, _extends({}, props, {
|
|
18
|
+
ref: ref
|
|
19
|
+
}), /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(Icon, {
|
|
20
|
+
icon: icon
|
|
21
|
+
})), /*#__PURE__*/React.createElement(ListItemText, {
|
|
22
|
+
primary: label
|
|
23
|
+
}));
|
|
24
|
+
});
|
|
25
|
+
Component.displayName = 'exportToText';
|
|
26
|
+
return Component;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export var exportToText = function exportToText(_ref) {
|
|
30
|
+
var exportedText = _ref.exportedText,
|
|
31
|
+
file = _ref.file;
|
|
32
|
+
|
|
33
|
+
var _getActionsI18n = getActionsI18n(),
|
|
34
|
+
t = _getActionsI18n.t;
|
|
35
|
+
|
|
36
|
+
var icon = ExportIcon;
|
|
37
|
+
var label = t('exportToText');
|
|
38
|
+
return {
|
|
39
|
+
name: 'exportToText',
|
|
40
|
+
icon: icon,
|
|
41
|
+
label: label,
|
|
42
|
+
displayCondition: function displayCondition() {
|
|
43
|
+
return !!exportedText;
|
|
44
|
+
},
|
|
45
|
+
Component: makeComponent(label, icon),
|
|
46
|
+
action: function () {
|
|
47
|
+
var _action = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
48
|
+
var blob, baseName;
|
|
49
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
50
|
+
while (1) {
|
|
51
|
+
switch (_context.prev = _context.next) {
|
|
52
|
+
case 0:
|
|
53
|
+
_context.prev = 0;
|
|
54
|
+
_context.next = 3;
|
|
55
|
+
return makePdfBlobFromText(exportedText);
|
|
56
|
+
|
|
57
|
+
case 3:
|
|
58
|
+
blob = _context.sent;
|
|
59
|
+
baseName = file !== null && file !== void 0 && file.name ? "".concat(file.name.replace(/\.[^/.]+$/, ''), "_export") : 'export';
|
|
60
|
+
downloadBlob(blob, "".concat(baseName, ".pdf"));
|
|
61
|
+
_context.next = 11;
|
|
62
|
+
break;
|
|
63
|
+
|
|
64
|
+
case 8:
|
|
65
|
+
_context.prev = 8;
|
|
66
|
+
_context.t0 = _context["catch"](0);
|
|
67
|
+
logger.error(_context.t0);
|
|
68
|
+
|
|
69
|
+
case 11:
|
|
70
|
+
case "end":
|
|
71
|
+
return _context.stop();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}, _callee, null, [[0, 8]]);
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
function action() {
|
|
78
|
+
return _action.apply(this, arguments);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return action;
|
|
82
|
+
}()
|
|
83
|
+
};
|
|
84
|
+
};
|
|
@@ -5,4 +5,5 @@ export function makeBase64FromFile(file: File): Promise<string | null>;
|
|
|
5
5
|
export function fileToArrayBuffer(file: File): Promise<ArrayBuffer>;
|
|
6
6
|
export function addFileToPdf(pdfDoc: PDFDocument, file: File): Promise<ArrayBuffer>;
|
|
7
7
|
export function makePdfBlob({ client, docs, fetchBlobFileById }: object): Promise<object>;
|
|
8
|
+
export function downloadBlob(blob: Blob, filename: string): void;
|
|
8
9
|
import { PDFDocument } from "pdf-lib/cjs/api";
|
|
@@ -475,4 +475,23 @@ export var makePdfBlob = /*#__PURE__*/function () {
|
|
|
475
475
|
return function makePdfBlob(_x11) {
|
|
476
476
|
return _ref11.apply(this, arguments);
|
|
477
477
|
};
|
|
478
|
-
}();
|
|
478
|
+
}();
|
|
479
|
+
/**
|
|
480
|
+
* Trigger a browser download for a given blob.
|
|
481
|
+
*
|
|
482
|
+
* @param {Blob} blob - File content
|
|
483
|
+
* @param {string} filename - Desired filename
|
|
484
|
+
* @returns {void}
|
|
485
|
+
*/
|
|
486
|
+
|
|
487
|
+
export var downloadBlob = function downloadBlob(blob, filename) {
|
|
488
|
+
if (!blob || !filename) return;
|
|
489
|
+
var url = URL.createObjectURL(blob);
|
|
490
|
+
var a = document.createElement('a');
|
|
491
|
+
a.href = url;
|
|
492
|
+
a.download = filename;
|
|
493
|
+
a.style.display = 'none';
|
|
494
|
+
document.body.appendChild(a);
|
|
495
|
+
a.click();
|
|
496
|
+
a.remove();
|
|
497
|
+
};
|
|
@@ -12,4 +12,5 @@ export { viewInContacts } from './viewInContacts';
|
|
|
12
12
|
export { viewInDrive } from './viewInDrive';
|
|
13
13
|
export { copyToClipboard } from './copyToClipboard';
|
|
14
14
|
export { editAttribute } from './editAttribute';
|
|
15
|
-
export { others } from './others';
|
|
15
|
+
export { others } from './others';
|
|
16
|
+
export { exportToText } from './exportToText';
|
|
@@ -26,7 +26,8 @@ var en = {
|
|
|
26
26
|
success: "Copied to clipboard",
|
|
27
27
|
error: "Cannot copy to clipboard"
|
|
28
28
|
},
|
|
29
|
-
call: "Call"
|
|
29
|
+
call: "Call",
|
|
30
|
+
exportToText: "Export as text"
|
|
30
31
|
};
|
|
31
32
|
var fr = {
|
|
32
33
|
menu: "Menu",
|
|
@@ -55,7 +56,8 @@ var fr = {
|
|
|
55
56
|
success: "Copi\xE9 dans le presse-papier",
|
|
56
57
|
error: "Impossible de copier dans le presse-papier"
|
|
57
58
|
},
|
|
58
|
-
call: "Appeler"
|
|
59
|
+
call: "Appeler",
|
|
60
|
+
exportToText: "Exporter en texte"
|
|
59
61
|
};
|
|
60
62
|
var ru = {
|
|
61
63
|
menu: "\u041C\u0435\u043D\u044E",
|
|
@@ -84,7 +86,8 @@ var ru = {
|
|
|
84
86
|
success: "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u043E \u0432 \u0431\u0443\u0444\u0435\u0440 \u043E\u0431\u043C\u0435\u043D\u0430",
|
|
85
87
|
error: "\u041D\u0435 \u0443\u0434\u0430\u0435\u0442\u0441\u044F \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432 \u0431\u0443\u0444\u0435\u0440 \u043E\u0431\u043C\u0435\u043D\u0430"
|
|
86
88
|
},
|
|
87
|
-
call: "\u0417\u0432\u043E\u043D\u0438\u0442\u044C"
|
|
89
|
+
call: "\u0417\u0432\u043E\u043D\u0438\u0442\u044C",
|
|
90
|
+
exportToText: "\u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u0430\u043A \u0442\u0435\u043A\u0441\u0442"
|
|
88
91
|
};
|
|
89
92
|
var vi = {
|
|
90
93
|
menu: "Menu",
|
|
@@ -113,7 +116,8 @@ var vi = {
|
|
|
113
116
|
success: "\u0110\xE3 sao ch\xE9p v\xE0o clipboard",
|
|
114
117
|
error: "Kh\xF4ng th\u1EC3 sao ch\xE9p v\xE0o clipboard"
|
|
115
118
|
},
|
|
116
|
-
call: "G\u1ECDi"
|
|
119
|
+
call: "G\u1ECDi",
|
|
120
|
+
exportToText: "Xu\u1EA5t d\u01B0\u1EDBi d\u1EA1ng v\u0103n b\u1EA3n"
|
|
117
121
|
};
|
|
118
122
|
export var locales = {
|
|
119
123
|
en: en,
|