@fibery/ui-kit 1.40.0 → 1.40.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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @fibery/ui-kit
2
2
 
3
+ ## 1.40.1
4
+
5
+ ### Patch Changes
6
+
7
+ - f44f43b: add asChild to <Button/>
8
+
3
9
  ## 1.40.0
4
10
 
5
11
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fibery/ui-kit",
3
- "version": "1.40.0",
3
+ "version": "1.40.1",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "dependencies": {
@@ -11,6 +11,7 @@
11
11
  "@radix-ui/react-context-menu": "2.2.1",
12
12
  "@radix-ui/react-dropdown-menu": "2.1.1",
13
13
  "@radix-ui/react-navigation-menu": "1.2.1",
14
+ "@radix-ui/react-slot": "1.2.4",
14
15
  "@radix-ui/react-toast": "1.2.2",
15
16
  "@radix-ui/react-toggle": "1.1.10",
16
17
  "@radix-ui/react-toggle-group": "1.1.11",
@@ -57,10 +58,10 @@
57
58
  "devDependencies": {
58
59
  "@babel/core": "7.28.5",
59
60
  "@babel/runtime": "7.28.4",
60
- "@testing-library/dom": "8.19.1",
61
+ "@testing-library/dom": "10.4.1",
61
62
  "@testing-library/jest-dom": "6.9.1",
62
- "@testing-library/react": "13.4.0",
63
- "@testing-library/user-event": "13.5.0",
63
+ "@testing-library/react": "16.3.1",
64
+ "@testing-library/user-event": "14.6.1",
64
65
  "@types/chroma-js": "2.1.3",
65
66
  "@types/color-hash": "1.0.2",
66
67
  "@types/history": "4.7.11",
@@ -82,8 +83,8 @@
82
83
  "svgo": "2.8.0",
83
84
  "typescript": "5.9.3",
84
85
  "unist-util-reduce": "0.2.2",
85
- "@fibery/babel-preset": "7.4.1",
86
- "@fibery/eslint-config": "8.6.2"
86
+ "@fibery/eslint-config": "8.6.2",
87
+ "@fibery/babel-preset": "7.4.1"
87
88
  },
88
89
  "jest": {
89
90
  "testEnvironment": "jsdom",
package/src/appIcons.json CHANGED
@@ -13063,6 +13063,16 @@
13063
13063
  "imageUrl": "https://images-temp.fibery.io/ui/appIcons/linear.svg",
13064
13064
  "file": "linear.svg"
13065
13065
  },
13066
+ {
13067
+ "name": "Stripe",
13068
+ "short_names": ["stripe"],
13069
+ "customCategory": "Integrations",
13070
+ "text": "",
13071
+ "emoticons": [],
13072
+ "keywords": ["logo", "brand", "integration", "stripe"],
13073
+ "imageUrl": "https://images-temp.fibery.io/ui/appIcons/stripe.svg",
13074
+ "file": "stripe.svg"
13075
+ },
13066
13076
  {
13067
13077
  "name": "Openion",
13068
13078
  "short_names": ["openion"],
package/src/box.tsx CHANGED
@@ -296,7 +296,7 @@ const defaultRadius = {
296
296
  rb: border.radius6,
297
297
  lb: border.radius6,
298
298
  };
299
- type Props = HTMLProps<HTMLDivElement> & {
299
+ export type BoxProps = HTMLProps<HTMLDivElement> & {
300
300
  as?: React.ElementType;
301
301
  } & {
302
302
  ref?: Ref<HTMLDivElement>;
@@ -342,7 +342,7 @@ type Props = HTMLProps<HTMLDivElement> & {
342
342
  * Fibery system card-like container with all mouse, focus and selected states support.
343
343
  * States described at: https://www.figma.com/file/Qff2eEFvZhjpxSqeFD5n58/FI---UI-Projects?type=design&node-id=4085%3A30506&mode=design&t=UvkBPcZSg5hKi86D-1
344
344
  */
345
- export const Box = forwardRef<HTMLDivElement, Props>((props, ref) => {
345
+ export const Box = forwardRef<HTMLDivElement, BoxProps>((props, ref) => {
346
346
  const {
347
347
  selected,
348
348
  done,
@@ -1,4 +1,5 @@
1
1
  import {css, CSSProperties, cx} from "@linaria/core";
2
+ import {Slot} from "@radix-ui/react-slot";
2
3
  import {forwardRef} from "react";
3
4
  import {themeVars} from "../design-system";
4
5
  import {iconColorVar} from "../icons/Icon";
@@ -12,6 +13,7 @@ export type BaseButtonProps = {
12
13
  color?: ButtonColor;
13
14
  pressed?: boolean;
14
15
  supportMobile?: boolean;
16
+ asChild?: boolean;
15
17
  } & React.ComponentPropsWithRef<"button">;
16
18
 
17
19
  export const xLargeButtonHeight = 40;
@@ -36,6 +38,7 @@ export const baseButton = css`
36
38
 
37
39
  @media (any-hover: hover) {
38
40
  &:hover:not(:disabled) {
41
+ color: var(--fibery-button-text-color);
39
42
  background-color: var(--fibery-button-hover-color);
40
43
  }
41
44
  }
@@ -112,13 +115,25 @@ const getColors = (variant: ButtonVariant, color: ButtonColor) => {
112
115
 
113
116
  export const BaseButton = forwardRef<HTMLButtonElement, BaseButtonProps>(
114
117
  (
115
- {variant = "solid", color = "accent", type = "button", className, children, style, pressed, ...buttonProps},
118
+ {
119
+ variant = "solid",
120
+ color = "accent",
121
+ type = "button",
122
+ className,
123
+ children,
124
+ style,
125
+ pressed,
126
+ asChild,
127
+ ...buttonProps
128
+ },
116
129
  ref
117
130
  ) => {
118
131
  const colors = getColors(variant, color);
119
132
 
133
+ const Component = asChild ? Slot : "button";
134
+
120
135
  return (
121
- <button
136
+ <Component
122
137
  style={{...colors, ...style}}
123
138
  aria-pressed={pressed || buttonProps["aria-pressed"]}
124
139
  data-variant={variant}
@@ -129,7 +144,7 @@ export const BaseButton = forwardRef<HTMLButtonElement, BaseButtonProps>(
129
144
  {...buttonProps}
130
145
  >
131
146
  {children}
132
- </button>
147
+ </Component>
133
148
  );
134
149
  }
135
150
  );
@@ -1,11 +1,12 @@
1
1
  import {css, cx} from "@linaria/core";
2
+ import {Slot, Slottable} from "@radix-ui/react-slot";
2
3
  import {forwardRef} from "react";
3
4
  import {border, fontWeight, space, textStyles} from "../design-system";
4
5
  import {iconSizeVar} from "../icons/Icon";
5
6
  import SpinnerIcon from "../icons/react/Spinner";
6
- import {BaseButton, BaseButtonProps, ButtonSize, xLargeButtonHeight} from "./base-button";
7
- import {useIsSupportHardwareKeyboard} from "../use-is-support-hardware-keyboard";
8
7
  import {useIsPhone} from "../use-is-phone";
8
+ import {useIsSupportHardwareKeyboard} from "../use-is-support-hardware-keyboard";
9
+ import {BaseButton, BaseButtonProps, ButtonSize, xLargeButtonHeight} from "./base-button";
9
10
 
10
11
  export type ButtonProps = {
11
12
  size?: ButtonSize;
@@ -193,12 +194,16 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
193
194
  disabled,
194
195
  shortcut,
195
196
  fullWidth,
197
+ asChild,
196
198
  ...buttonProps
197
199
  },
198
200
  ref
199
201
  ) => {
200
202
  const isSupportHardwareKeyboard = useIsSupportHardwareKeyboard();
201
203
  const isPhone = useIsPhone();
204
+
205
+ const Component = asChild ? Slot : "button";
206
+
202
207
  return (
203
208
  <BaseButton
204
209
  ref={ref}
@@ -213,12 +218,15 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
213
218
  iconEnd && withIconEnd,
214
219
  !children && withoutChildren
215
220
  )}
221
+ asChild
216
222
  {...buttonProps}
217
223
  >
218
- {pending ? <SpinnerIcon /> : iconStart}
219
- {children}
220
- {iconEnd}
221
- {shortcut && isSupportHardwareKeyboard ? <span className={shortcutContainer}>{shortcut}</span> : null}
224
+ <Component>
225
+ {pending ? <SpinnerIcon /> : iconStart}
226
+ <Slottable>{children}</Slottable>
227
+ {iconEnd}
228
+ {shortcut && isSupportHardwareKeyboard ? <span className={shortcutContainer}>{shortcut}</span> : null}
229
+ </Component>
222
230
  </BaseButton>
223
231
  );
224
232
  }
@@ -9,7 +9,10 @@ import {useIsPhone} from "../use-is-phone";
9
9
  export type IconButtonProps = {
10
10
  size?: ButtonSize;
11
11
  pending?: boolean;
12
- } & BaseButtonProps;
12
+
13
+ /** NOTE: it won't work properly together with `pending` prop. TODO: figure out how to use Slottable correctly (position spinner as absolute above?) */
14
+ asChild?: boolean;
15
+ } & Omit<BaseButtonProps, "asChild">;
13
16
 
14
17
  export const iconButton = css`
15
18
  display: flex;
package/src/dot.tsx ADDED
@@ -0,0 +1,36 @@
1
+ import {css, CSSProperties, cx} from "@linaria/core";
2
+ import {space, themeVars} from "./design-system";
3
+ import {useMemo} from "react";
4
+
5
+ const dotColorVar = "--fibery-dot-color";
6
+
7
+ const dotCss = css`
8
+ background-color: var(${dotColorVar});
9
+ border-radius: 50%;
10
+
11
+ &[data-size="small"] {
12
+ width: ${space.s4}px;
13
+ height: ${space.s4}px;
14
+ }
15
+
16
+ &[data-size="medium"] {
17
+ width: ${space.s6}px;
18
+ height: ${space.s6}px;
19
+ }
20
+ `;
21
+
22
+ type Props = {
23
+ className?: string;
24
+ color?: string;
25
+ size?: "small" | "medium";
26
+ } & React.ComponentProps<"div">;
27
+
28
+ export const Dot = ({className, color = themeVars.active, size = "small", style, ...props}: Props) => {
29
+ const colors: CSSProperties = useMemo(() => {
30
+ return {
31
+ [dotColorVar]: color,
32
+ };
33
+ }, [color]);
34
+
35
+ return <div className={cx(className, dotCss)} style={{...colors, ...style}} data-size={size} {...props} />;
36
+ };
@@ -102,6 +102,8 @@ export type FileItemProps = {
102
102
  disabled?: boolean;
103
103
  };
104
104
 
105
+ export const minFileTileWidth = 120;
106
+
105
107
  export function FileItem(props: FileItemProps) {
106
108
  const {onDownloadClick, onRemoveClick} = props;
107
109
  const {name, thumbnailUrl, status, previewData: preview, contentType} = props.data;
@@ -133,7 +135,7 @@ export function FileItem(props: FileItemProps) {
133
135
 
134
136
  useEffect(() => {
135
137
  if (!preview) {
136
- return;
138
+ return undefined;
137
139
  }
138
140
 
139
141
  if (zoomed) {
@@ -152,6 +154,10 @@ export function FileItem(props: FileItemProps) {
152
154
  actions: <FilePreviewActions url={preview.originalSrc} name={name} onDownloadClick={onDownloadClick} />,
153
155
  });
154
156
  }
157
+
158
+ return () => {
159
+ imagesRegistry.delete(preview.originalSrc);
160
+ };
155
161
  }, [galleryMethods, zoomed, preview, imagesRegistry, name, onDownloadClick]);
156
162
 
157
163
  const onContainerClick = useCallback(() => {
@@ -169,6 +175,7 @@ export function FileItem(props: FileItemProps) {
169
175
  css`
170
176
  flex: 1 0 0;
171
177
  height: 100%;
178
+ min-width: ${minFileTileWidth}px;
172
179
  `,
173
180
  isBackgroundReady &&
174
181
  css`
@@ -258,10 +265,9 @@ export function FileItem(props: FileItemProps) {
258
265
  </Icon>
259
266
  <div
260
267
  className={css`
261
- align-content: center;
262
-
263
268
  display: flex;
264
- align-items: center;
269
+ width: 100%;
270
+ justify-content: center;
265
271
  gap: 10px;
266
272
  flex-shrink: 0;
267
273
  color: ${themeVars.colorTextMenuItem};
@@ -272,8 +278,6 @@ export function FileItem(props: FileItemProps) {
272
278
  <FileTitle
273
279
  title={name}
274
280
  className={css`
275
- -webkit-line-clamp: 1;
276
- -webkit-box-orient: vertical;
277
281
  overflow: hidden;
278
282
  text-overflow: ellipsis;
279
283
  `}
@@ -327,10 +331,10 @@ export function FileItem(props: FileItemProps) {
327
331
  <div
328
332
  className={css`
329
333
  display: flex;
334
+ width: 100%;
330
335
  align-self: flex-start;
331
336
  align-items: flex-end;
332
337
  text-overflow: ellipsis;
333
- //overflow: hidden;
334
338
  box-sizing: border-box;
335
339
  `}
336
340
  >
@@ -440,16 +444,12 @@ function FileTitle({title, className}: {title: string; className?: string}) {
440
444
  vertical-align: top;
441
445
  text-align: center;
442
446
  justify-content: center;
443
- word-break: break-word;
444
447
  overflow: hidden;
445
448
  font-size: ${fontSize.mini}px;
446
449
  font-weight: ${fontWeight.medium};
447
450
  line-height: ${lineHeight.heading};
448
451
  text-transform: none;
449
452
  text-overflow: ellipsis;
450
- -webkit-line-clamp: 1;
451
- -webkit-box-orient: vertical;
452
-
453
453
  &:hover {
454
454
  text-decoration: none;
455
455
  color: inherit;
@@ -463,7 +463,7 @@ function FileTitle({title, className}: {title: string; className?: string}) {
463
463
  display: flex;
464
464
  min-width: 0;
465
465
  align-items: center;
466
- max-width: 120px;
466
+ max-width: 180px;
467
467
  `}
468
468
  >
469
469
  <span
@@ -142,7 +142,7 @@ const htmlStyles = {
142
142
  paddingTop: space.s3,
143
143
  paddingBottom: space.s3,
144
144
  ...textStyles.big,
145
- lineHeight: lineHeight.text,
145
+ lineHeight: lineHeight.regular,
146
146
  },
147
147
  "& .fibery-rich-text-check-item": {
148
148
  marginTop: space.s3,
@@ -150,7 +150,7 @@ const htmlStyles = {
150
150
  paddingTop: space.s3,
151
151
  paddingBottom: space.s3,
152
152
  ...textStyles.big,
153
- lineHeight: lineHeight.text,
153
+ lineHeight: lineHeight.regular,
154
154
  },
155
155
  "& table": {
156
156
  marginTop: space.s8,
@@ -167,7 +167,7 @@ const htmlStyles = {
167
167
  paddingTop: space.s3,
168
168
  paddingBottom: space.s3,
169
169
  ...textStyles.big,
170
- lineHeight: lineHeight.text,
170
+ lineHeight: lineHeight.regular,
171
171
  },
172
172
  },
173
173
  "& .code-block": {
@@ -223,14 +223,12 @@ const htmlStyles = {
223
223
  },
224
224
  },
225
225
  "& > *:first-child": {
226
- marginTop: 0,
226
+ marginTop: space.s3,
227
227
  paddingTop: space.s3,
228
228
  paddingBottom: space.s3,
229
229
  },
230
230
  "& > *:last-child": {
231
- marginBottom: 0,
232
- paddingTop: space.s3,
233
- paddingBottom: space.s3,
231
+ marginBottom: space.s3,
234
232
  },
235
233
  "& > .fibery-rich-text-image-block:last-child": {
236
234
  marginBottom: space.s4,
@@ -352,7 +350,7 @@ const smallHtmlStyles = {
352
350
  paddingTop: space.s2,
353
351
  paddingBottom: space.s2,
354
352
  ...textStyles.regular,
355
- lineHeight: lineHeight.text,
353
+ lineHeight: lineHeight.regular,
356
354
  },
357
355
  "& .fibery-rich-text-check-item": {
358
356
  marginTop: space.s2,
@@ -360,7 +358,7 @@ const smallHtmlStyles = {
360
358
  paddingTop: space.s2,
361
359
  paddingBottom: space.s2,
362
360
  ...textStyles.regular,
363
- lineHeight: lineHeight.text,
361
+ lineHeight: lineHeight.regular,
364
362
  },
365
363
  "& table": {
366
364
  marginTop: space.s6,
@@ -377,7 +375,7 @@ const smallHtmlStyles = {
377
375
  paddingTop: space.s2,
378
376
  paddingBottom: space.s2,
379
377
  ...textStyles.regular,
380
- lineHeight: lineHeight.text,
378
+ lineHeight: lineHeight.regular,
381
379
  },
382
380
  },
383
381
  "& .code-block": {
@@ -439,8 +437,6 @@ const smallHtmlStyles = {
439
437
  },
440
438
  "& > *:last-child": {
441
439
  marginBottom: 0,
442
- paddingTop: space.s2,
443
- paddingBottom: space.s2,
444
440
  },
445
441
  "& > .fibery-rich-text-image-block:last-child": {
446
442
  marginBottom: space.s2,
@@ -546,7 +542,7 @@ const chatHtmlStyles = {
546
542
  paddingTop: space.s2,
547
543
  paddingBottom: space.s2,
548
544
  ...textStyles.regular,
549
- lineHeight: lineHeight.text,
545
+ lineHeight: lineHeight.regular,
550
546
  [`${mobileRootSelector} &`]: {
551
547
  ...textStyles.big,
552
548
  },
@@ -557,7 +553,7 @@ const chatHtmlStyles = {
557
553
  paddingTop: space.s2,
558
554
  paddingBottom: space.s2,
559
555
  ...textStyles.regular,
560
- lineHeight: lineHeight.text,
556
+ lineHeight: lineHeight.regular,
561
557
  },
562
558
  "& table": {
563
559
  marginTop: space.s4,
@@ -574,7 +570,7 @@ const chatHtmlStyles = {
574
570
  paddingTop: space.s2,
575
571
  paddingBottom: space.s2,
576
572
  ...textStyles.regular,
577
- lineHeight: lineHeight.text,
573
+ lineHeight: lineHeight.regular,
578
574
  },
579
575
  },
580
576
  "& .code-block": {
@@ -0,0 +1,8 @@
1
+
2
+ // This icon file is generated automatically.
3
+
4
+ import { IconDefinition } from '../types';
5
+
6
+ const QuickFilter: IconDefinition = {"icon":{"type":"root","children":[{"type":"element","tagName":"svg","properties":{"width":20,"height":20,"fill":"none"},"children":[{"type":"element","tagName":"path","properties":{"d":"M15.25 2A2.75 2.75 0 0 1 18 4.75v10.5A2.75 2.75 0 0 1 15.25 18H4.75A2.75 2.75 0 0 1 2 15.25V4.75A2.75 2.75 0 0 1 4.75 2h10.5ZM4.75 3.5c-.69 0-1.25.56-1.25 1.25v10.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25V4.75c0-.69-.56-1.25-1.25-1.25H4.75Zm6.5 8.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1 0-1.5h2.5Zm1-2.75a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5h4.5Zm1-2.75a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h6.5Z","fill":"#000"},"children":[]}],"metadata":""}]},"name":"quick-filter"};
7
+
8
+ export default QuickFilter;
@@ -0,0 +1,8 @@
1
+
2
+ // This icon file is generated automatically.
3
+
4
+ import { IconDefinition } from '../types';
5
+
6
+ const QuickFilterPersonal: IconDefinition = {"icon":{"type":"root","children":[{"type":"element","tagName":"svg","properties":{"width":20,"height":20,"fill":"none"},"children":[{"type":"element","tagName":"path","properties":{"d":"M2.75 11.25a.75.75 0 0 1 .75.75v3.25c0 .69.56 1.25 1.25 1.25H8A.75.75 0 0 1 8 18H4.75A2.75 2.75 0 0 1 2 15.25V12a.75.75 0 0 1 .75-.75Zm14.5 0A.75.75 0 0 1 18 12v3.25A2.75 2.75 0 0 1 15.25 18H12a.75.75 0 0 1 0-1.5h3.25c.69 0 1.25-.56 1.25-1.25V12a.75.75 0 0 1 .75-.75Zm-6 .75a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1 0-1.5h2.5Zm1-2.75a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5h4.5ZM8 2a.75.75 0 0 1 0 1.5H4.75c-.69 0-1.25.56-1.25 1.25V8A.75.75 0 0 1 2 8V4.75A2.75 2.75 0 0 1 4.75 2H8Zm7.25 0A2.75 2.75 0 0 1 18 4.75V8a.75.75 0 0 1-1.5 0V4.75c0-.69-.56-1.25-1.25-1.25H12A.75.75 0 0 1 12 2h3.25Zm-2 4.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h6.5Z","fill":"#000"},"children":[]}],"metadata":""}]},"name":"quick-filter-personal"};
7
+
8
+ export default QuickFilterPersonal;
@@ -246,6 +246,8 @@ export { default as PresentPlay } from './PresentPlay';
246
246
  export { default as PresentStop } from './PresentStop';
247
247
  export { default as PrivateItems } from './PrivateItems';
248
248
  export { default as Question } from './Question';
249
+ export { default as QuickFilterPersonal } from './QuickFilterPersonal';
250
+ export { default as QuickFilter } from './QuickFilter';
249
251
  export { default as ReadOnly } from './ReadOnly';
250
252
  export { default as Refresh } from './Refresh';
251
253
  export { default as RemovePeople } from './RemovePeople';
@@ -0,0 +1,13 @@
1
+ // This icon file is generated automatically.
2
+
3
+ import {forwardRef} from 'react';
4
+ import QuickFilterSvg from '../ast/QuickFilter';
5
+ import { Icon } from '../Icon';
6
+ import { IconBaseProps } from '../types';
7
+
8
+ const QuickFilter = forwardRef<SVGSVGElement, IconBaseProps>(function QuickFilter(
9
+ props: IconBaseProps,
10
+ ref: React.Ref<SVGSVGElement>
11
+ ) {return <Icon {...props} className={props.className} ref={ref} icon={QuickFilterSvg} />});
12
+
13
+ export default QuickFilter;
@@ -0,0 +1,13 @@
1
+ // This icon file is generated automatically.
2
+
3
+ import {forwardRef} from 'react';
4
+ import QuickFilterPersonalSvg from '../ast/QuickFilterPersonal';
5
+ import { Icon } from '../Icon';
6
+ import { IconBaseProps } from '../types';
7
+
8
+ const QuickFilterPersonal = forwardRef<SVGSVGElement, IconBaseProps>(function QuickFilterPersonal(
9
+ props: IconBaseProps,
10
+ ref: React.Ref<SVGSVGElement>
11
+ ) {return <Icon {...props} className={props.className} ref={ref} icon={QuickFilterPersonalSvg} />});
12
+
13
+ export default QuickFilterPersonal;
@@ -246,6 +246,8 @@ export { default as PresentPlay } from './PresentPlay';
246
246
  export { default as PresentStop } from './PresentStop';
247
247
  export { default as PrivateItems } from './PrivateItems';
248
248
  export { default as Question } from './Question';
249
+ export { default as QuickFilterPersonal } from './QuickFilterPersonal';
250
+ export { default as QuickFilter } from './QuickFilter';
249
251
  export { default as ReadOnly } from './ReadOnly';
250
252
  export { default as Refresh } from './Refresh';
251
253
  export { default as RemovePeople } from './RemovePeople';
@@ -0,0 +1,3 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M2.75 11.25C3.16421 11.25 3.5 11.5858 3.5 12V15.25C3.5 15.9404 4.05964 16.5 4.75 16.5H8C8.41421 16.5 8.75 16.8358 8.75 17.25C8.75 17.6642 8.41421 18 8 18H4.75C3.23122 18 2 16.7688 2 15.25V12C2 11.5858 2.33579 11.25 2.75 11.25ZM17.25 11.25C17.6642 11.25 18 11.5858 18 12V15.25C18 16.7688 16.7688 18 15.25 18H12C11.5858 18 11.25 17.6642 11.25 17.25C11.25 16.8358 11.5858 16.5 12 16.5H15.25C15.9404 16.5 16.5 15.9404 16.5 15.25V12C16.5 11.5858 16.8358 11.25 17.25 11.25ZM11.25 12C11.6642 12 12 12.3358 12 12.75C12 13.1642 11.6642 13.5 11.25 13.5H8.75C8.33579 13.5 8 13.1642 8 12.75C8 12.3358 8.33579 12 8.75 12H11.25ZM12.25 9.25C12.6642 9.25 13 9.58579 13 10C13 10.4142 12.6642 10.75 12.25 10.75H7.75C7.33579 10.75 7 10.4142 7 10C7 9.58579 7.33579 9.25 7.75 9.25H12.25ZM8 2C8.41421 2 8.75 2.33579 8.75 2.75C8.75 3.16421 8.41421 3.5 8 3.5H4.75C4.05964 3.5 3.5 4.05964 3.5 4.75V8C3.5 8.41421 3.16421 8.75 2.75 8.75C2.33579 8.75 2 8.41421 2 8V4.75C2 3.23122 3.23122 2 4.75 2H8ZM15.25 2C16.7688 2 18 3.23122 18 4.75V8C18 8.41421 17.6642 8.75 17.25 8.75C16.8358 8.75 16.5 8.41421 16.5 8V4.75C16.5 4.05964 15.9404 3.5 15.25 3.5H12C11.5858 3.5 11.25 3.16421 11.25 2.75C11.25 2.33579 11.5858 2 12 2H15.25ZM13.25 6.5C13.6642 6.5 14 6.83579 14 7.25C14 7.66421 13.6642 8 13.25 8H6.75C6.33579 8 6 7.66421 6 7.25C6 6.83579 6.33579 6.5 6.75 6.5H13.25Z" fill="black"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M15.25 2C16.7688 2 18 3.23122 18 4.75V15.25C18 16.7688 16.7688 18 15.25 18H4.75C3.23122 18 2 16.7688 2 15.25V4.75C2 3.23122 3.23122 2 4.75 2H15.25ZM4.75 3.5C4.05964 3.5 3.5 4.05964 3.5 4.75V15.25C3.5 15.9404 4.05964 16.5 4.75 16.5H15.25C15.9404 16.5 16.5 15.9404 16.5 15.25V4.75C16.5 4.05964 15.9404 3.5 15.25 3.5H4.75ZM11.25 12C11.6642 12 12 12.3358 12 12.75C12 13.1642 11.6642 13.5 11.25 13.5H8.75C8.33579 13.5 8 13.1642 8 12.75C8 12.3358 8.33579 12 8.75 12H11.25ZM12.25 9.25C12.6642 9.25 13 9.58579 13 10C13 10.4142 12.6642 10.75 12.25 10.75H7.75C7.33579 10.75 7 10.4142 7 10C7 9.58579 7.33579 9.25 7.75 9.25H12.25ZM13.25 6.5C13.6642 6.5 14 6.83579 14 7.25C14 7.66421 13.6642 8 13.25 8H6.75C6.33579 8 6 7.66421 6 7.25C6 6.83579 6.33579 6.5 6.75 6.5H13.25Z" fill="black"/>
3
+ </svg>
@@ -0,0 +1,71 @@
1
+ import {thumbnailsMimeTypesWhiteList} from "./thumbnails-mime-types-white-list";
2
+
3
+ export function getGallerySrc({
4
+ src,
5
+ contentType,
6
+ contentLength,
7
+ isPhone,
8
+ }: {
9
+ src: string;
10
+ contentType: string;
11
+ contentLength: number;
12
+ isPhone: boolean;
13
+ }): null | {
14
+ type: "iframe" | "video" | "image";
15
+ src: string;
16
+ } {
17
+ const isFiberyFile = src?.startsWith("/api/files");
18
+
19
+ if (!isPhone && isFiberyFile && contentType?.startsWith("text/") && contentLength < 2 * 1024 * 1024) {
20
+ const url = new URL(src, `${window.location}`);
21
+ url.searchParams.append("plain-text", "true");
22
+
23
+ return {
24
+ type: "iframe",
25
+ src: url.href,
26
+ };
27
+ }
28
+
29
+ if (!contentType || !thumbnailsMimeTypesWhiteList.has(contentType)) {
30
+ return null;
31
+ }
32
+
33
+ if (ImageContentTypes.includes(contentType)) {
34
+ return {
35
+ type: "image",
36
+ src,
37
+ };
38
+ }
39
+
40
+ if (VideoContentTypes.includes(contentType)) {
41
+ return {
42
+ type: "video",
43
+ src,
44
+ };
45
+ }
46
+
47
+ if (!isPhone && IframeContentTypes.includes(contentType)) {
48
+ return {
49
+ type: "iframe",
50
+ src: new URL(src, `${window.location}`).href,
51
+ };
52
+ }
53
+
54
+ return null;
55
+ }
56
+
57
+ const ImageContentTypes = [
58
+ "image/apng",
59
+ "image/png",
60
+ "image/jpeg",
61
+ "image/webp",
62
+ "image/avif",
63
+ "image/gif",
64
+ "image/x-icon",
65
+ "image/bmp",
66
+ "image/tiff",
67
+ "image/svg+xml",
68
+ ];
69
+
70
+ const VideoContentTypes = ["video/mp4", "video/quicktime"];
71
+ const IframeContentTypes = ["application/pdf"];
@@ -340,7 +340,7 @@ export function createPhotoSwipeLightbox(
340
340
  return photoSwipeLightbox;
341
341
  }
342
342
 
343
- function initGallery(
343
+ export function initGallery(
344
344
  imagesRegistry: Registry,
345
345
  {toastQueue, themeMode, isPhone}: {toastQueue: ToastQueue; themeMode: ThemeMode; isPhone: boolean}
346
346
  ) {
@@ -0,0 +1,17 @@
1
+ export const thumbnailsMimeTypesWhiteList = new Set([
2
+ "image/apng",
3
+ "image/png",
4
+ "image/jpeg",
5
+ "image/webp",
6
+ "image/avif",
7
+ "image/gif",
8
+ "image/x-icon",
9
+ "image/bmp",
10
+ "image/tiff",
11
+ "image/heic",
12
+ "image/svg+xml",
13
+ "video/mp4",
14
+ "video/quicktime",
15
+ "application/pdf",
16
+ "image/vnd.adobe.photoshop",
17
+ ]);