@noya-app/noya-designsystem 0.0.2

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 (73) hide show
  1. package/.turbo/turbo-build.log +17 -0
  2. package/CHANGELOG.md +7 -0
  3. package/README.md +1 -0
  4. package/dist/index.d.mts +1178 -0
  5. package/dist/index.d.ts +1178 -0
  6. package/dist/index.js +15651 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.mjs +15684 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/package.json +49 -0
  11. package/src/__tests__/__snapshots__/fuzzyScorer.test.ts.snap +41 -0
  12. package/src/__tests__/fuzzyScorer.test.ts +85 -0
  13. package/src/components/ActivityIndicator.tsx +44 -0
  14. package/src/components/Avatar.tsx +64 -0
  15. package/src/components/Button.tsx +209 -0
  16. package/src/components/Chip.tsx +214 -0
  17. package/src/components/ContextMenu.tsx +224 -0
  18. package/src/components/Dialog.tsx +143 -0
  19. package/src/components/Divider.tsx +40 -0
  20. package/src/components/DropdownMenu.tsx +208 -0
  21. package/src/components/FillInputField.tsx +43 -0
  22. package/src/components/FillPreviewBackground.tsx +132 -0
  23. package/src/components/GradientPicker.tsx +88 -0
  24. package/src/components/Grid.tsx +54 -0
  25. package/src/components/GridView.tsx +468 -0
  26. package/src/components/IconButton.tsx +46 -0
  27. package/src/components/InputField.tsx +568 -0
  28. package/src/components/InputFieldWithCompletions.tsx +477 -0
  29. package/src/components/Label.tsx +62 -0
  30. package/src/components/LabeledElementView.tsx +185 -0
  31. package/src/components/ListView.tsx +950 -0
  32. package/src/components/Popover.tsx +113 -0
  33. package/src/components/Progress.tsx +57 -0
  34. package/src/components/RadioGroup.tsx +163 -0
  35. package/src/components/ScrollArea.tsx +70 -0
  36. package/src/components/Select.tsx +152 -0
  37. package/src/components/Slider.tsx +82 -0
  38. package/src/components/Sortable.tsx +296 -0
  39. package/src/components/Spacer.tsx +29 -0
  40. package/src/components/Stack.tsx +142 -0
  41. package/src/components/Switch.tsx +67 -0
  42. package/src/components/Text.tsx +164 -0
  43. package/src/components/Toast.tsx +86 -0
  44. package/src/components/Tooltip.tsx +43 -0
  45. package/src/components/TreeView.tsx +85 -0
  46. package/src/components/internal/Menu.tsx +222 -0
  47. package/src/components/internal/TextInput.tsx +296 -0
  48. package/src/components/internal/__tests__/TextInput.test.tsx +144 -0
  49. package/src/contexts/DesignSystemConfiguration.tsx +57 -0
  50. package/src/contexts/DialogContext.tsx +190 -0
  51. package/src/contexts/GlobalInputBlurContext.tsx +61 -0
  52. package/src/contexts/ImageDataContext.tsx +44 -0
  53. package/src/hooks/__tests__/mergeEventHandlers.test.ts +47 -0
  54. package/src/hooks/mergeEventHandlers.ts +55 -0
  55. package/src/hooks/useHover.ts +173 -0
  56. package/src/hooks/useObjectURL.ts +22 -0
  57. package/src/hooks/usePlatform.ts +13 -0
  58. package/src/index.tsx +77 -0
  59. package/src/mediaQuery.ts +13 -0
  60. package/src/theme/dark.ts +37 -0
  61. package/src/theme/index.ts +17 -0
  62. package/src/theme/light.ts +178 -0
  63. package/src/utils/breakpoints.ts +45 -0
  64. package/src/utils/completions.ts +21 -0
  65. package/src/utils/createSectionedMenu.ts +38 -0
  66. package/src/utils/fuzzyScorer.ts +105 -0
  67. package/src/utils/getGradientBackground.tsx +33 -0
  68. package/src/utils/handleNudge.ts +30 -0
  69. package/src/utils/mouseEvent.ts +7 -0
  70. package/src/utils/sketchColor.ts +34 -0
  71. package/src/utils/sketchPattern.ts +29 -0
  72. package/src/utils/withSeparatorElements.ts +31 -0
  73. package/tsconfig.json +3 -0
@@ -0,0 +1,132 @@
1
+ import { Sketch } from "@noya-app/noya-file-format";
2
+ // import { useSketchImage } from 'noya-renderer';
3
+ import React, { memo, useMemo } from "react";
4
+ import styled, { useTheme } from "styled-components";
5
+ import { useImageData } from "../contexts/ImageDataContext";
6
+ import { useObjectURL } from "../hooks/useObjectURL";
7
+ import { getGradientBackground } from "../utils/getGradientBackground";
8
+ import { sketchColorToRgbaString } from "../utils/sketchColor";
9
+ import { SketchPattern } from "../utils/sketchPattern";
10
+
11
+ const dotsHorizontalSvg = (fillColor: string) => `
12
+ <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 15 15' fill='${fillColor}'>
13
+ <path d='M3.625 7.5C3.625 8.12132 3.12132 8.625 2.5 8.625C1.87868 8.625 1.375 8.12132 1.375 7.5C1.375 6.87868 1.87868 6.375 2.5 6.375C3.12132 6.375 3.625 6.87868 3.625 7.5ZM8.625 7.5C8.625 8.12132 8.12132 8.625 7.5 8.625C6.87868 8.625 6.375 8.12132 6.375 7.5C6.375 6.87868 6.87868 6.375 7.5 6.375C8.12132 6.375 8.625 6.87868 8.625 7.5ZM12.5 8.625C13.1213 8.625 13.625 8.12132 13.625 7.5C13.625 6.87868 13.1213 6.375 12.5 6.375C11.8787 6.375 11.375 6.87868 11.375 7.5C11.375 8.12132 11.8787 8.625 12.5 8.625Z'></path>
14
+ </svg>
15
+ `;
16
+
17
+ const Background = styled.span<{ background: string }>(({ background }) => ({
18
+ background,
19
+ position: "absolute",
20
+ inset: 0,
21
+ }));
22
+
23
+ const HorizontalDotsBackground = memo(function HorizontalDotsBackground() {
24
+ const { inputBackground, placeholderDots } = useTheme().colors;
25
+
26
+ const background = useMemo(
27
+ () =>
28
+ [
29
+ `center url("data:image/svg+xml;utf8,${dotsHorizontalSvg(
30
+ placeholderDots
31
+ )}") no-repeat`,
32
+ inputBackground,
33
+ ].join(","),
34
+ [inputBackground, placeholderDots]
35
+ );
36
+
37
+ return <Background background={background} />;
38
+ });
39
+
40
+ function getPatternSizeAndPosition(
41
+ fillType: Sketch.PatternFillType,
42
+ tileScale: number
43
+ ) {
44
+ switch (fillType) {
45
+ case Sketch.PatternFillType.Fit:
46
+ return "center / contain";
47
+ case Sketch.PatternFillType.Tile:
48
+ return `top left / ${tileScale * 100}%`;
49
+ case Sketch.PatternFillType.Fill:
50
+ return "center / cover";
51
+ case Sketch.PatternFillType.Stretch:
52
+ return "center / 100% 100%";
53
+ }
54
+ }
55
+
56
+ export const PatternPreviewBackground = memo(function PatternPreviewBackground({
57
+ fillType,
58
+ tileScale,
59
+ imageRef,
60
+ }: {
61
+ fillType: Sketch.PatternFillType;
62
+ tileScale: number;
63
+ imageRef: string;
64
+ }) {
65
+ const image = useImageData(imageRef);
66
+
67
+ const url = useObjectURL(image);
68
+
69
+ const size = getPatternSizeAndPosition(fillType, tileScale);
70
+
71
+ const background = useMemo(
72
+ () =>
73
+ [
74
+ size,
75
+ `url(${url})`,
76
+ fillType === Sketch.PatternFillType.Tile ? "repeat" : "no-repeat",
77
+ ].join(" "),
78
+ [fillType, size, url]
79
+ );
80
+
81
+ return <Background background={background} />;
82
+ });
83
+
84
+ const ColorPreviewBackground = memo(function ColorPreviewBackground({
85
+ color,
86
+ }: {
87
+ color: Sketch.Color;
88
+ }) {
89
+ const background = useMemo(() => sketchColorToRgbaString(color), [color]);
90
+
91
+ return <Background background={background} />;
92
+ });
93
+
94
+ const GradientPreviewBackground = memo(function GradientPreviewBackground({
95
+ gradient,
96
+ }: {
97
+ gradient: Sketch.Gradient;
98
+ }) {
99
+ const background = useMemo(
100
+ () => getGradientBackground(gradient.stops, gradient.gradientType, 180),
101
+ [gradient.gradientType, gradient.stops]
102
+ );
103
+
104
+ return <Background background={background} />;
105
+ });
106
+
107
+ interface Props {
108
+ value?: Sketch.Color | Sketch.Gradient | SketchPattern;
109
+ }
110
+
111
+ export const FillPreviewBackground = memo(function FillPreviewBackground({
112
+ value,
113
+ }: Props) {
114
+ if (!value) return <HorizontalDotsBackground />;
115
+
116
+ switch (value._class) {
117
+ case "color":
118
+ return <ColorPreviewBackground color={value} />;
119
+ case "gradient":
120
+ return <GradientPreviewBackground gradient={value} />;
121
+ case "pattern":
122
+ if (!value.image) return null;
123
+
124
+ return (
125
+ <PatternPreviewBackground
126
+ fillType={value.patternFillType}
127
+ tileScale={value.patternTileScale}
128
+ imageRef={value.image._ref}
129
+ />
130
+ );
131
+ }
132
+ });
@@ -0,0 +1,88 @@
1
+ import {
2
+ Alpha,
3
+ ColorModel,
4
+ Gradient,
5
+ Hue,
6
+ ColorPicker as NoyaColorPicker,
7
+ RgbaColor,
8
+ Saturation,
9
+ equalColorObjects,
10
+ hsvaToRgba,
11
+ rgbaToHsva,
12
+ } from '@noya-app/noya-colorpicker';
13
+ import type { Sketch } from '@noya-app/noya-file-format';
14
+ import React, { memo, useCallback, useMemo } from 'react';
15
+ import { Spacer } from '../components/Spacer';
16
+ import { rgbaToSketchColor, sketchColorToRgba } from '../utils/sketchColor';
17
+
18
+ interface Props {
19
+ value: Sketch.GradientStop[];
20
+ selectedStop: number;
21
+ onChangeColor: (color: Sketch.Color) => void;
22
+ onChangePosition: (position: number) => void;
23
+ onAdd: (color: Sketch.Color, position: number) => void;
24
+ onDelete: () => void;
25
+ onSelectStop: (index: number) => void;
26
+ }
27
+
28
+ export const GradientPicker = memo(function GradientPicker({
29
+ value,
30
+ selectedStop,
31
+ onChangeColor,
32
+ onChangePosition,
33
+ onAdd,
34
+ onDelete,
35
+ onSelectStop,
36
+ }: Props) {
37
+ const colorModel: ColorModel<RgbaColor> = useMemo(
38
+ () => ({
39
+ defaultColor: { r: 0, g: 0, b: 0, a: 1 },
40
+ toHsva: rgbaToHsva,
41
+ fromHsva: hsvaToRgba,
42
+ equal: equalColorObjects,
43
+ }),
44
+ [],
45
+ );
46
+
47
+ const rgbaColor = useMemo(
48
+ () => sketchColorToRgba(value[selectedStop].color),
49
+ [value, selectedStop],
50
+ );
51
+
52
+ const handleChangeColor = useCallback(
53
+ (value: RgbaColor) => {
54
+ onChangeColor(rgbaToSketchColor(value));
55
+ },
56
+ [onChangeColor],
57
+ );
58
+
59
+ const handleAddGradientStop = useCallback(
60
+ (value: RgbaColor, position: number) => {
61
+ onAdd(rgbaToSketchColor(value), position);
62
+ },
63
+ [onAdd],
64
+ );
65
+
66
+ return (
67
+ <NoyaColorPicker
68
+ onChange={handleChangeColor}
69
+ colorModel={colorModel}
70
+ color={rgbaColor}
71
+ >
72
+ <Gradient
73
+ gradients={value}
74
+ selectedStop={selectedStop}
75
+ onSelectStop={onSelectStop}
76
+ onChangePosition={onChangePosition}
77
+ onAdd={handleAddGradientStop}
78
+ onDelete={onDelete}
79
+ />
80
+ <Spacer.Vertical size={10} />
81
+ <Saturation />
82
+ <Spacer.Vertical size={12} />
83
+ <Hue />
84
+ <Spacer.Vertical size={5} />
85
+ <Alpha />
86
+ </NoyaColorPicker>
87
+ );
88
+ });
@@ -0,0 +1,54 @@
1
+ import styled from 'styled-components';
2
+ import { Colors } from '../theme';
3
+
4
+ export type GridProps = {
5
+ columns?: string;
6
+ rows?: string;
7
+ alignItems?: 'start' | 'center' | 'end';
8
+ justifyItems?: 'start' | 'center' | 'end';
9
+ placeItems?: 'start' | 'center' | 'end';
10
+ width?: number | string;
11
+ minWidth?: number | string;
12
+ maxWidth?: number | string;
13
+ height?: number | string;
14
+ minHeight?: number | string;
15
+ maxHeight?: number | string;
16
+ padding?: number | string;
17
+ paddingX?: number | string;
18
+ paddingXStart?: number | string;
19
+ paddingXEnd?: number | string;
20
+ paddingY?: number | string;
21
+ paddingYStart?: number | string;
22
+ paddingYEnd?: number | string;
23
+ gap?: number | string;
24
+ gapX?: number | string;
25
+ gapY?: number | string;
26
+ background?: keyof Colors;
27
+ };
28
+
29
+ const Grid = styled.div<GridProps>((props) => ({
30
+ display: 'grid',
31
+ gridTemplateColumns: props.columns,
32
+ gridTemplateRows: props.rows,
33
+ alignItems: props.alignItems,
34
+ justifyItems: props.justifyItems,
35
+ width: props.width,
36
+ minWidth: props.minWidth ?? 0,
37
+ maxWidth: props.maxWidth,
38
+ height: props.height,
39
+ minHeight: props.minHeight ?? 0,
40
+ maxHeight: props.maxHeight,
41
+ padding: props.padding,
42
+ paddingInline: props.paddingX,
43
+ paddingInlineStart: props.paddingXStart,
44
+ paddingInlineEnd: props.paddingXEnd,
45
+ paddingBlock: props.paddingY,
46
+ paddingBlockStart: props.paddingYStart,
47
+ paddingBlockEnd: props.paddingYEnd,
48
+ gap: props.gap,
49
+ gapRow: props.gapX,
50
+ gapColumn: props.gapY,
51
+ background: props.background,
52
+ }));
53
+
54
+ export default Grid;