cozy-ui 102.0.0 → 102.1.1
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 +15 -0
- package/package.json +2 -1
- package/react/ActionsMenu/Actions/helpers.js +162 -0
- package/react/ActionsMenu/Actions/print.js +26 -19
- package/react/BottomSheet/BottomSheet.jsx +2 -2
- package/react/BottomSheet/README.md +1 -1
- package/react/BottomSheet/helpers.js +1 -1
- package/react/BottomSheet/helpers.spec.js +1 -1
- package/react/CozyDialogs/Readme.md +0 -41
- package/react/Dialog/DialogEffects.spec.tsx +5 -2
- package/react/Dialog/DialogEffects.ts +8 -5
- package/react/deprecated/ActionMenu/ActionMenuEffects.ts +6 -4
- package/react/deprecated/Modal/ModalEffects.ts +2 -1
- package/react/hooks/useSetFlagshipUi/helpers.js +149 -0
- package/react/hooks/useSetFlagshipUi/useSetFlagshipUI.ts +7 -3
- package/transpiled/react/ActionsMenu/Actions/helpers.js +410 -0
- package/transpiled/react/ActionsMenu/Actions/print.js +64 -30
- package/transpiled/react/BottomSheet/BottomSheet.js +5 -7
- package/transpiled/react/BottomSheet/helpers.js +1 -1
- package/transpiled/react/Dialog/DialogEffects.js +4 -2
- package/transpiled/react/deprecated/ActionMenu/ActionMenuEffects.js +2 -1
- package/transpiled/react/deprecated/Modal/ModalEffects.js +2 -1
- package/transpiled/react/hooks/useSetFlagshipUi/helpers.d.ts +18 -0
- package/transpiled/react/hooks/useSetFlagshipUi/helpers.js +143 -0
- package/transpiled/react/hooks/useSetFlagshipUi/useSetFlagshipUI.js +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [102.1.1](https://github.com/cozy/cozy-ui/compare/v102.1.0...v102.1.1) (2024-01-29)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **BottomSheet:** Default offset value wasn't good if flagship immersive [secure] ([b1551d2](https://github.com/cozy/cozy-ui/commit/b1551d2))
|
|
7
|
+
|
|
8
|
+
# [102.1.0](https://github.com/cozy/cozy-ui/compare/v102.0.0...v102.1.0) (2024-01-25)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **Action:** Print can now deal with multiple docs ([ee5695d](https://github.com/cozy/cozy-ui/commit/ee5695d))
|
|
14
|
+
* Add pdf-lib package ([9b363e1](https://github.com/cozy/cozy-ui/commit/9b363e1))
|
|
15
|
+
|
|
1
16
|
# [102.0.0](https://github.com/cozy/cozy-ui/compare/v101.2.0...v102.0.0) (2024-01-23)
|
|
2
17
|
|
|
3
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-ui",
|
|
3
|
-
"version": "102.
|
|
3
|
+
"version": "102.1.1",
|
|
4
4
|
"description": "Cozy apps UI SDK",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -171,6 +171,7 @@
|
|
|
171
171
|
"mui-bottom-sheet": "https://github.com/cozy/mui-bottom-sheet.git#v1.0.9",
|
|
172
172
|
"node-polyglot": "^2.2.2",
|
|
173
173
|
"normalize.css": "^8.0.0",
|
|
174
|
+
"pdf-lib": "1.17.1",
|
|
174
175
|
"piwik-react-router": "0.12.1",
|
|
175
176
|
"react-chartjs-2": "4.1.0",
|
|
176
177
|
"react-markdown": "^4.0.8",
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { PDFDocument } from 'pdf-lib'
|
|
2
|
+
import { fetchBlobFileById } from 'cozy-client/dist/models/file'
|
|
3
|
+
|
|
4
|
+
// Should guarantee good resolution for different uses (printing, downloading, etc.)
|
|
5
|
+
const MAX_RESIZE_IMAGE_SIZE = 3840
|
|
6
|
+
|
|
1
7
|
/**
|
|
2
8
|
* Make array of actions for ActionsItems component
|
|
3
9
|
*
|
|
@@ -82,3 +88,159 @@ export const makeBase64FromFile = async file => {
|
|
|
82
88
|
}
|
|
83
89
|
})
|
|
84
90
|
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {HTMLImageElement} image
|
|
94
|
+
* @param {number} [maxSizeInPixel] - Maximum size before being resized
|
|
95
|
+
* @returns {number}
|
|
96
|
+
*/
|
|
97
|
+
const getImageScaleRatio = (image, maxSize) => {
|
|
98
|
+
const longerSideSizeInPixel = Math.max(image.height, image.width)
|
|
99
|
+
let scaleRatio = 1
|
|
100
|
+
if (maxSize < longerSideSizeInPixel) {
|
|
101
|
+
scaleRatio = maxSize / longerSideSizeInPixel
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return scaleRatio
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @param {object} opts
|
|
109
|
+
* @param {string} opts.base64 - Base64 of image
|
|
110
|
+
* @param {string} opts.type - Type of image
|
|
111
|
+
* @param {number} opts.maxSize - Maximum size before being resized
|
|
112
|
+
* @returns {Promise<string>}
|
|
113
|
+
*/
|
|
114
|
+
const resizeImage = async ({
|
|
115
|
+
base64: fileDataUri,
|
|
116
|
+
type: fileType,
|
|
117
|
+
maxSize
|
|
118
|
+
}) => {
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
const newImage = new Image()
|
|
121
|
+
newImage.src = fileDataUri
|
|
122
|
+
newImage.onerror = reject
|
|
123
|
+
newImage.onload = () => {
|
|
124
|
+
const canvas = document.createElement('canvas')
|
|
125
|
+
const scaleRatio = getImageScaleRatio(newImage, maxSize)
|
|
126
|
+
const scaledWidth = scaleRatio * newImage.width
|
|
127
|
+
const scaledHeight = scaleRatio * newImage.height
|
|
128
|
+
|
|
129
|
+
canvas.width = scaledWidth
|
|
130
|
+
canvas.height = scaledHeight
|
|
131
|
+
canvas
|
|
132
|
+
.getContext('2d')
|
|
133
|
+
.drawImage(newImage, 0, 0, scaledWidth, scaledHeight)
|
|
134
|
+
|
|
135
|
+
resolve(canvas.toDataURL(fileType))
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @param {File} file
|
|
142
|
+
* @returns {Promise<string>}
|
|
143
|
+
*/
|
|
144
|
+
const fileToDataUri = async file => {
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
let reader = new FileReader()
|
|
147
|
+
reader.onerror = reject
|
|
148
|
+
reader.onload = e => resolve(e.target.result)
|
|
149
|
+
reader.readAsDataURL(file)
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param {PDFDocument} pdfDoc
|
|
155
|
+
* @param {File} file
|
|
156
|
+
* @returns {Promise<void>}
|
|
157
|
+
*/
|
|
158
|
+
const addImageToPdf = async (pdfDoc, file) => {
|
|
159
|
+
const fileDataUri = await fileToDataUri(file)
|
|
160
|
+
const resizedImage = await resizeImage({
|
|
161
|
+
base64: fileDataUri,
|
|
162
|
+
type: file.type,
|
|
163
|
+
maxSize: MAX_RESIZE_IMAGE_SIZE
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
let img
|
|
167
|
+
if (file.type === 'image/png') img = await pdfDoc.embedPng(resizedImage)
|
|
168
|
+
if (file.type === 'image/jpeg') img = await pdfDoc.embedJpg(resizedImage)
|
|
169
|
+
|
|
170
|
+
const page = pdfDoc.addPage([img.width, img.height])
|
|
171
|
+
const { width: pageWidth, height: pageHeight } = page.getSize()
|
|
172
|
+
page.drawImage(img, {
|
|
173
|
+
x: pageWidth / 2 - img.width / 2,
|
|
174
|
+
y: pageHeight / 2 - img.height / 2,
|
|
175
|
+
width: img.width,
|
|
176
|
+
height: img.height
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @param {File} file
|
|
182
|
+
* @returns {Promise<ArrayBuffer>}
|
|
183
|
+
*/
|
|
184
|
+
const fileToArrayBuffer = async file => {
|
|
185
|
+
if ('arrayBuffer' in file) return await file.arrayBuffer()
|
|
186
|
+
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
let reader = new FileReader()
|
|
189
|
+
reader.onerror = reject
|
|
190
|
+
reader.onload = e => resolve(new Uint8Array(e.target.result))
|
|
191
|
+
reader.readAsArrayBuffer(file)
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @param {PDFDocument} pdfDoc
|
|
197
|
+
* @param {File} file
|
|
198
|
+
* @returns {Promise<void>}
|
|
199
|
+
*/
|
|
200
|
+
const addPdfToPdf = async (pdfDoc, file) => {
|
|
201
|
+
const pdfToAdd = await fileToArrayBuffer(file)
|
|
202
|
+
const document = await PDFDocument.load(pdfToAdd)
|
|
203
|
+
const copiedPages = await pdfDoc.copyPages(
|
|
204
|
+
document,
|
|
205
|
+
document.getPageIndices()
|
|
206
|
+
)
|
|
207
|
+
copiedPages.forEach(page => pdfDoc.addPage(page))
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {PDFDocument} pdfDoc - Instance of PDFDocument
|
|
212
|
+
* @param {File} file - File to add in pdf
|
|
213
|
+
* @returns {Promise<ArrayBuffer>} - Data of pdf generated
|
|
214
|
+
*/
|
|
215
|
+
export const addFileToPdf = async (pdfDoc, file) => {
|
|
216
|
+
if (file.type === 'application/pdf') {
|
|
217
|
+
await addPdfToPdf(pdfDoc, file)
|
|
218
|
+
} else {
|
|
219
|
+
await addImageToPdf(pdfDoc, file)
|
|
220
|
+
}
|
|
221
|
+
const pdfDocBytes = await pdfDoc.save()
|
|
222
|
+
|
|
223
|
+
return pdfDocBytes
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Fetches file from docs list and return a blob of pdf
|
|
228
|
+
* @param {import('cozy-client/types/CozyClient').default} client - Instance of CozyClient
|
|
229
|
+
* @param {array} docs - Docs from an io.cozy.xxx doctypes
|
|
230
|
+
* @returns {Promise<object>} Blob of generated Pdf
|
|
231
|
+
*/
|
|
232
|
+
export const makePdfBlob = async (client, docs) => {
|
|
233
|
+
const pdfDoc = await PDFDocument.create()
|
|
234
|
+
|
|
235
|
+
for (const doc of docs) {
|
|
236
|
+
const blob = await fetchBlobFileById(client, doc._id)
|
|
237
|
+
await addFileToPdf(pdfDoc, blob)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const pdfBytes = await pdfDoc.save()
|
|
241
|
+
|
|
242
|
+
const bytes = new Uint8Array(pdfBytes)
|
|
243
|
+
const blob = new Blob([bytes], { type: 'application/pdf' })
|
|
244
|
+
|
|
245
|
+
return blob
|
|
246
|
+
}
|
|
@@ -3,7 +3,7 @@ import React, { forwardRef } from 'react'
|
|
|
3
3
|
import logger from 'cozy-logger'
|
|
4
4
|
import { fetchBlobFileById, isFile } from 'cozy-client/dist/models/file'
|
|
5
5
|
|
|
6
|
-
import { makeBase64FromFile } from './helpers'
|
|
6
|
+
import { makeBase64FromFile, makePdfBlob } from './helpers'
|
|
7
7
|
import PrinterIcon from '../../Icons/Printer'
|
|
8
8
|
import { getActionsI18n } from './locales/withActionsLocales'
|
|
9
9
|
import ActionsMenuItem from '../ActionsMenuItem'
|
|
@@ -21,33 +21,40 @@ export const print = () => {
|
|
|
21
21
|
icon,
|
|
22
22
|
label,
|
|
23
23
|
disabled: docs => docs.length === 0,
|
|
24
|
-
displayCondition: docs => isFile(
|
|
24
|
+
displayCondition: docs => docs.every(doc => isFile(doc)),
|
|
25
25
|
action: async (docs, { client, webviewIntent }) => {
|
|
26
|
-
const
|
|
26
|
+
const isSingleDoc = docs.length === 1
|
|
27
|
+
const firstDoc = docs[0]
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
try {
|
|
30
|
+
// in flagship app
|
|
31
|
+
if (webviewIntent) {
|
|
32
|
+
const blob = isSingleDoc
|
|
33
|
+
? await fetchBlobFileById(client, firstDoc._id)
|
|
34
|
+
: await makePdfBlob(client, docs)
|
|
31
35
|
const base64 = await makeBase64FromFile(blob)
|
|
32
36
|
|
|
33
37
|
return webviewIntent.call('print', base64)
|
|
34
|
-
} catch (error) {
|
|
35
|
-
logger.error(
|
|
36
|
-
`Error trying to print document with Flagship App: ${JSON.stringify(
|
|
37
|
-
error
|
|
38
|
-
)}`
|
|
39
|
-
)
|
|
40
38
|
}
|
|
41
|
-
}
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
// not in flagship app
|
|
41
|
+
let docUrl = ''
|
|
42
|
+
if (isSingleDoc) {
|
|
43
|
+
docUrl = await client
|
|
44
|
+
.collection('io.cozy.files')
|
|
45
|
+
.getDownloadLinkById(firstDoc._id, firstDoc.name)
|
|
46
|
+
} else {
|
|
47
|
+
const blob = await makePdfBlob(client, docs)
|
|
48
|
+
docUrl = URL.createObjectURL(blob)
|
|
49
|
+
}
|
|
47
50
|
|
|
48
|
-
window.open(
|
|
51
|
+
window.open(docUrl, '_blank')
|
|
49
52
|
} catch (error) {
|
|
50
|
-
logger.error(
|
|
53
|
+
logger.error(
|
|
54
|
+
`Error trying to print document ${
|
|
55
|
+
webviewIntent ? 'inside flagship appp' : 'outside flagship app'
|
|
56
|
+
}: ${JSON.stringify(error)}`
|
|
57
|
+
)
|
|
51
58
|
}
|
|
52
59
|
},
|
|
53
60
|
Component: forwardRef((props, ref) => {
|
|
@@ -13,7 +13,7 @@ import { useMutationObserver, useTimeoutWhen } from 'rooks'
|
|
|
13
13
|
import Fade from '@material-ui/core/Fade'
|
|
14
14
|
import Portal from '@material-ui/core/Portal'
|
|
15
15
|
|
|
16
|
-
import { getFlagshipMetadata } from '
|
|
16
|
+
import { getFlagshipMetadata } from '../hooks/useSetFlagshipUi/helpers'
|
|
17
17
|
|
|
18
18
|
import { useSetFlagshipUI } from '../hooks/useSetFlagshipUi/useSetFlagshipUI'
|
|
19
19
|
import CozyTheme, { useCozyTheme } from '../providers/CozyTheme'
|
|
@@ -392,7 +392,7 @@ BottomSheet.defaultProps = {
|
|
|
392
392
|
toolbarProps: {},
|
|
393
393
|
backdrop: false,
|
|
394
394
|
offset:
|
|
395
|
-
(getFlagshipMetadata().immersive && getFlagshipMetadata().navbarHeight)
|
|
395
|
+
(getFlagshipMetadata().immersive && getFlagshipMetadata().navbarHeight) || 0
|
|
396
396
|
}
|
|
397
397
|
|
|
398
398
|
BottomSheet.propTypes = {
|
|
@@ -94,7 +94,7 @@ const initialState = {
|
|
|
94
94
|
isSecondBottomSheetDisplayed: false,
|
|
95
95
|
mediumHeight: isTesting() ? 450 : undefined,
|
|
96
96
|
mediumHeightRatio: undefined,
|
|
97
|
-
offset:
|
|
97
|
+
offset: undefined
|
|
98
98
|
}
|
|
99
99
|
const showBottomSheet = () => setState({ isBottomSheetDisplayed: true })
|
|
100
100
|
const hideBottomSheet = () => setState({ isBottomSheetDisplayed: false })
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { getFlagshipMetadata } from 'cozy-device-helper'
|
|
3
2
|
|
|
4
3
|
import { ANIMATION_DURATION } from './constants'
|
|
5
4
|
import { getSafeAreaValue } from '../helpers/getSafeArea'
|
|
5
|
+
import { getFlagshipMetadata } from '../hooks/useSetFlagshipUi/helpers'
|
|
6
6
|
|
|
7
7
|
export const computeToolbarHeight = (toolbarProps = {}) => {
|
|
8
8
|
const { ref, height } = toolbarProps
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
jest.mock('../helpers/getSafeArea', () => ({
|
|
13
13
|
getSafeAreaValue: jest.fn().mockReturnValue(15)
|
|
14
14
|
}))
|
|
15
|
-
jest.mock('
|
|
15
|
+
jest.mock('../hooks/useSetFlagshipUi/helpers', () => ({
|
|
16
16
|
getFlagshipMetadata: jest.fn(() => ({ navbarHeight: 10 }))
|
|
17
17
|
}))
|
|
18
18
|
const windowSpy = jest.spyOn(window, 'window', 'get')
|
|
@@ -208,50 +208,9 @@ const initialVariants = [{
|
|
|
208
208
|
withBackground: false
|
|
209
209
|
}]
|
|
210
210
|
|
|
211
|
-
// The goal of this method is to simulate the
|
|
212
|
-
// immersive mode of the flagship app. So we
|
|
213
|
-
// add the flagship-app class to the body and
|
|
214
|
-
// we set 2 css variables:
|
|
215
|
-
// flagship-top-height
|
|
216
|
-
// flagship-bottom-height
|
|
217
|
-
const setFlagshipVars = () => {
|
|
218
|
-
const root = document.getElementsByTagName('body')[0]
|
|
219
|
-
root.style.setProperty('--flagship-top-height', "40px")
|
|
220
|
-
root.style.setProperty('--flagship-bottom-height', "40px")
|
|
221
|
-
root.classList.add('flagship-app')
|
|
222
|
-
|
|
223
|
-
const statusBarDiv = document.createElement("div")
|
|
224
|
-
statusBarDiv.style.cssText = "position:fixed;top:0;height:40px;z-index:10000000;background-color:red;width:100%"
|
|
225
|
-
// and give it some content
|
|
226
|
-
const statusBarDivContent = document.createTextNode("Top Status Bar with clock")
|
|
227
|
-
|
|
228
|
-
// add the text node to the newly created div
|
|
229
|
-
statusBarDiv.appendChild(statusBarDivContent)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const bottomBarDiv = document.createElement("div")
|
|
233
|
-
bottomBarDiv.style.cssText = "position:fixed;bottom:0;height:40px;z-index:10000000;background-color:red;width:100%"
|
|
234
|
-
// and give it some content
|
|
235
|
-
const bottomBarDivContent = document.createTextNode("BottomBar")
|
|
236
|
-
|
|
237
|
-
// add the text node to the newly created div
|
|
238
|
-
bottomBarDiv.appendChild(bottomBarDivContent)
|
|
239
|
-
|
|
240
|
-
// add the newly created element and its content into the DOM
|
|
241
|
-
const currentDiv = document.getElementById("rsg-root")
|
|
242
|
-
document.body.insertBefore(statusBarDiv, currentDiv)
|
|
243
|
-
document.body.insertBefore(bottomBarDiv, currentDiv)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
211
|
;
|
|
247
212
|
|
|
248
213
|
<DemoProvider>
|
|
249
|
-
<Button
|
|
250
|
-
className="u-mb-1"
|
|
251
|
-
variant="secondary"
|
|
252
|
-
label={'Simulate Immersive Flagship Mode'}
|
|
253
|
-
onClick={() => setFlagshipVars()}
|
|
254
|
-
/>
|
|
255
214
|
<Variants initialVariants={initialVariants}>
|
|
256
215
|
{variant => (
|
|
257
216
|
<>
|
|
@@ -238,8 +238,11 @@ it('should provide the inversed UI when Cozybar is not black on white, but white
|
|
|
238
238
|
})
|
|
239
239
|
|
|
240
240
|
jest.mock('cozy-device-helper', () => ({
|
|
241
|
-
isFlagshipApp: (): boolean => true
|
|
242
|
-
|
|
241
|
+
isFlagshipApp: (): boolean => true
|
|
242
|
+
}))
|
|
243
|
+
jest.mock('../hooks/useSetFlagshipUi/helpers', () => ({
|
|
244
|
+
getFlagshipMetadata: (): Record<string, never> => ({}),
|
|
245
|
+
setRsgFlagshipElements: (): null => null
|
|
243
246
|
}))
|
|
244
247
|
|
|
245
248
|
const onOpenMountExpected = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getLuminance, Theme, useTheme } from '@material-ui/core'
|
|
2
2
|
import { useEffect } from 'react'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { isFlagshipApp } from 'cozy-device-helper'
|
|
5
5
|
import { useWebviewIntent } from 'cozy-intent'
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
ThemeColor,
|
|
10
10
|
parseArg
|
|
11
11
|
} from '../hooks/useSetFlagshipUi/useSetFlagshipUI'
|
|
12
|
+
import { getFlagshipMetadata } from '../hooks/useSetFlagshipUi/helpers'
|
|
13
|
+
import { isRsg } from '../hooks/useSetFlagshipUi/helpers'
|
|
12
14
|
|
|
13
15
|
interface DialogEffectsOptions {
|
|
14
16
|
cozybar?: Element | null
|
|
@@ -192,7 +194,8 @@ export const useDialogSetFlagshipUI = (
|
|
|
192
194
|
}, [open, webviewIntent]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
193
195
|
}
|
|
194
196
|
|
|
195
|
-
export const useDialogEffects =
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
export const useDialogEffects =
|
|
198
|
+
isFlagshipApp() || isRsg
|
|
199
|
+
? useHook
|
|
200
|
+
: // eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
201
|
+
(): void => {}
|
|
@@ -7,6 +7,7 @@ import { Theme, useTheme } from '@material-ui/core'
|
|
|
7
7
|
import { isFlagshipApp } from 'cozy-device-helper'
|
|
8
8
|
|
|
9
9
|
import { useSetFlagshipUI } from '../../hooks/useSetFlagshipUi/useSetFlagshipUI'
|
|
10
|
+
import { isRsg } from '../../hooks/useSetFlagshipUi/helpers'
|
|
10
11
|
|
|
11
12
|
const getBottomBackground = (theme: Theme): string => {
|
|
12
13
|
const sidebar = document.getElementById('sidebar')
|
|
@@ -40,7 +41,8 @@ const useHook = (): void => {
|
|
|
40
41
|
)
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
export const useActionMenuEffects =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
export const useActionMenuEffects =
|
|
45
|
+
isFlagshipApp() || isRsg
|
|
46
|
+
? useHook
|
|
47
|
+
: // eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
48
|
+
(): void => {}
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import { Theme, useTheme } from '@material-ui/core'
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { isFlagshipApp } from 'cozy-device-helper'
|
|
8
8
|
|
|
9
9
|
import { useSetFlagshipUI } from '../../hooks/useSetFlagshipUi/useSetFlagshipUI'
|
|
10
|
+
import { getFlagshipMetadata } from '../../hooks/useSetFlagshipUi/helpers'
|
|
10
11
|
|
|
11
12
|
const getTopBackground = (theme: Theme, cozyBar: Element | null): string =>
|
|
12
13
|
(cozyBar && getComputedStyle(cozyBar).getPropertyValue('background-color')) ||
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// eslint-disable-next-line no-unused-vars
|
|
2
|
+
import { FlagshipUI } from './useSetFlagshipUI'
|
|
3
|
+
import { getFlagshipMetadata as getFlagshipMetadataFromDeviceHelper } from 'cozy-device-helper'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The goal of this method is to simulate the immersive mode of the flagship app.
|
|
7
|
+
* So we add the flagship-app class to the body and we set css variables:
|
|
8
|
+
* If the "contained" mode is activated, it simulates an classic app behavior
|
|
9
|
+
* If the "immersive" mode is activated, it simulates a fullscreen app like Home
|
|
10
|
+
*/
|
|
11
|
+
export const addFlagshipElements = () => {
|
|
12
|
+
const root = document.getElementsByTagName('body')[0]
|
|
13
|
+
root.style.setProperty('--flagship-top-height', '40px')
|
|
14
|
+
root.style.setProperty('--flagship-top-bgcolor', 'white') // used only for cozy-ui docs
|
|
15
|
+
root.style.setProperty('--flagship-top-overlay', 'transparent') // used only for cozy-ui docs
|
|
16
|
+
root.style.setProperty('--flagship-top-color', 'black') // used only for cozy-ui docs
|
|
17
|
+
root.style.setProperty('--flagship-bottom-height', '40px')
|
|
18
|
+
root.style.setProperty('--flagship-bottom-bgcolor', 'white') // used only for cozy-ui docs
|
|
19
|
+
root.style.setProperty('--flagship-bottom-overlay', 'transparent') // used only for cozy-ui docs
|
|
20
|
+
root.style.setProperty('--flagship-bottom-color', 'black') // used only for cozy-ui docs
|
|
21
|
+
root.classList.add('flagship-app')
|
|
22
|
+
|
|
23
|
+
// create status bar
|
|
24
|
+
const statusBarDiv = document.createElement('div')
|
|
25
|
+
statusBarDiv.setAttribute('id', 'flagshipStatusBar')
|
|
26
|
+
statusBarDiv.style.cssText =
|
|
27
|
+
'position:fixed;top:0;height:var(--flagship-top-height);z-index:10000000;color:var(--flagship-top-color);background-color:var(--flagship-top-bgcolor);width:100%;display:flex;align-items:center;justify-content:center'
|
|
28
|
+
// create status bar overlay
|
|
29
|
+
const statusBarOverlay = document.createElement('div')
|
|
30
|
+
statusBarOverlay.setAttribute('id', 'flagshipStatusBarOverlay')
|
|
31
|
+
statusBarOverlay.style.cssText =
|
|
32
|
+
'position:absolute;top:0;left:0;width:100%;height:100%;z-index:-1;background-color:var(--flagship-top-overlay)'
|
|
33
|
+
statusBarDiv.appendChild(statusBarOverlay)
|
|
34
|
+
// create status bar text
|
|
35
|
+
const statusBarText = document.createElement('div')
|
|
36
|
+
statusBarText.setAttribute('id', 'flagshipStatusBarText')
|
|
37
|
+
statusBarText.innerText = 'Flagship Top Status Bar with clock'
|
|
38
|
+
statusBarDiv.appendChild(statusBarText)
|
|
39
|
+
|
|
40
|
+
// create nav bar
|
|
41
|
+
const navBarDiv = document.createElement('div')
|
|
42
|
+
navBarDiv.setAttribute('id', 'flagshipNavBar')
|
|
43
|
+
navBarDiv.style.cssText =
|
|
44
|
+
'position:fixed;bottom:0;height:var(--flagship-bottom-height);z-index:10000000;color:var(--flagship-bottom-color);background-color:var(--flagship-bottom-bgcolor);width:100%;display:flex;align-items:center;justify-content:center'
|
|
45
|
+
// create nav bar overlay
|
|
46
|
+
const navBarOverlay = document.createElement('div')
|
|
47
|
+
navBarOverlay.setAttribute('id', 'flagshipNavBarOverlay')
|
|
48
|
+
navBarOverlay.style.cssText =
|
|
49
|
+
'position:absolute;top:0;left:0;width:100%;height:100%;z-index:-1;background-color:var(--flagship-bottom-overlay)'
|
|
50
|
+
navBarDiv.appendChild(navBarOverlay)
|
|
51
|
+
// create nav bar text
|
|
52
|
+
const navBarText = document.createElement('div')
|
|
53
|
+
navBarText.setAttribute('id', 'flagshipNavBarText')
|
|
54
|
+
navBarText.innerText = 'Flagship Nav Bar'
|
|
55
|
+
navBarDiv.appendChild(navBarText)
|
|
56
|
+
|
|
57
|
+
// add status and nav bar and its content into the DOM
|
|
58
|
+
const currentDiv = document.getElementById('rsg-root')
|
|
59
|
+
document.body.insertBefore(statusBarDiv, currentDiv)
|
|
60
|
+
document.body.insertBefore(navBarDiv, currentDiv)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Remove fake DOM element that simulates native Status and Nav bar
|
|
65
|
+
*/
|
|
66
|
+
export const removeFlagshipElements = () => {
|
|
67
|
+
const root = document.getElementsByTagName('body')[0]
|
|
68
|
+
root.style.removeProperty('--flagship-top-height')
|
|
69
|
+
root.style.removeProperty('--flagship-top-bgcolor')
|
|
70
|
+
root.style.removeProperty('--flagship-top-overlay')
|
|
71
|
+
root.style.removeProperty('--flagship-top-color')
|
|
72
|
+
root.style.removeProperty('--flagship-bottom-height')
|
|
73
|
+
root.style.removeProperty('--flagship-bottom-bgcolor')
|
|
74
|
+
root.style.removeProperty('--flagship-bottom-overlay')
|
|
75
|
+
root.style.removeProperty('--flagship-bottom-color')
|
|
76
|
+
root.classList.remove('flagship-app')
|
|
77
|
+
|
|
78
|
+
document.getElementById('flagshipStatusBar')?.remove()
|
|
79
|
+
document.getElementById('flagshipNavBar')?.remove()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Whether we are in cozy-ui documentation (Rsg is for ReactStyleGuide)
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
export const isRsg = !!document.getElementById('rsg-root')
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Overrides flagship metadata
|
|
90
|
+
* See https://github.com/cozy/cozy-libs/blob/master/packages/cozy-device-helper/src/flagship.ts#L13
|
|
91
|
+
*/
|
|
92
|
+
export const getFlagshipMetadata = isRsg
|
|
93
|
+
? () => ({
|
|
94
|
+
immersive:
|
|
95
|
+
JSON.parse(localStorage.getItem('flagship-app'))?.contained === 'off' ||
|
|
96
|
+
false,
|
|
97
|
+
statusBarHeight: 40,
|
|
98
|
+
navbarHeight: 40
|
|
99
|
+
})
|
|
100
|
+
: getFlagshipMetadataFromDeviceHelper
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Set the css values for Status and Nav bar inside cozy-ui documentation
|
|
104
|
+
* see https://github.com/cozy/cozy-libs/blob/master/packages/cozy-intent/src/api/models/applications.ts#L33
|
|
105
|
+
* @param {undefined | Partial<FlagshipUI>} param0
|
|
106
|
+
* @returns
|
|
107
|
+
*/
|
|
108
|
+
export const setRsgFlagshipElements = ({
|
|
109
|
+
topBackground,
|
|
110
|
+
topOverlay,
|
|
111
|
+
topTheme,
|
|
112
|
+
bottomBackground,
|
|
113
|
+
bottomOverlay,
|
|
114
|
+
bottomTheme
|
|
115
|
+
} = {}) => {
|
|
116
|
+
if (!isRsg) return
|
|
117
|
+
|
|
118
|
+
const root = document.getElementsByTagName('body')[0]
|
|
119
|
+
|
|
120
|
+
if (topBackground) {
|
|
121
|
+
root.style.setProperty('--flagship-top-bgcolor', topBackground)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (topOverlay) {
|
|
125
|
+
root.style.setProperty('--flagship-top-overlay', topOverlay)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (topTheme) {
|
|
129
|
+
root.style.setProperty(
|
|
130
|
+
'--flagship-top-color',
|
|
131
|
+
topTheme === 'dark' ? 'black' : 'white'
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (bottomBackground) {
|
|
136
|
+
root.style.setProperty('--flagship-bottom-bgcolor', bottomBackground)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (bottomOverlay) {
|
|
140
|
+
root.style.setProperty('--flagship-bottom-overlay', bottomOverlay)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (bottomTheme) {
|
|
144
|
+
root.style.setProperty(
|
|
145
|
+
'--flagship-bottom-color',
|
|
146
|
+
bottomTheme === 'dark' ? 'black' : 'white'
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -8,6 +8,8 @@ import { useWebviewIntent } from 'cozy-intent'
|
|
|
8
8
|
import { FlagshipUI as IntentInterface } from 'cozy-intent/dist/api/models/applications'
|
|
9
9
|
import { WebviewService } from 'cozy-intent/dist/api/services/WebviewService'
|
|
10
10
|
|
|
11
|
+
import { setRsgFlagshipElements } from './helpers'
|
|
12
|
+
|
|
11
13
|
export enum ThemeColor {
|
|
12
14
|
Dark = 'dark',
|
|
13
15
|
Light = 'light'
|
|
@@ -23,11 +25,13 @@ export const parseArg = (
|
|
|
23
25
|
arg?: FlagshipUI,
|
|
24
26
|
caller?: string
|
|
25
27
|
): void => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const sanitized = isObject(arg) && pickBy(arg, identity)
|
|
28
|
+
const sanitized = isObject(arg) ? pickBy(arg, identity) : undefined
|
|
29
29
|
const validUI = !isEmpty(sanitized) && sanitized
|
|
30
30
|
|
|
31
|
+
setRsgFlagshipElements(sanitized)
|
|
32
|
+
|
|
33
|
+
if (!webviewIntent) return
|
|
34
|
+
|
|
31
35
|
validUI && webviewIntent.call('setFlagshipUI', validUI, caller)
|
|
32
36
|
}
|
|
33
37
|
|