A design system in a box. hip-ui.tngl.io/docs/introduction
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add colors to canvas example

+316 -200
+316 -200
apps/docs/src/showcases/canvas-editor.tsx
··· 37 37 TriangleRight, 38 38 } from "lucide-react"; 39 39 import { createContext, memo, use, useState } from "react"; 40 - import { useDragAndDrop } from "react-aria-components"; 40 + import { Key, useDragAndDrop } from "react-aria-components"; 41 41 import { 42 42 ArrowShapeUtil, 43 43 Editor, ··· 75 75 import { uiColor } from "../components/theme/semantic-color.stylex"; 76 76 import { shadow } from "../components/theme/shadow.stylex"; 77 77 import { spacing } from "../components/theme/spacing.stylex"; 78 + import { 79 + ColorSwatchPicker, 80 + ColorSwatchPickerItem, 81 + } from "@/components/color-swatch-picker"; 78 82 79 83 const styles = stylex.create({ 80 84 main: { ··· 618 622 ); 619 623 } 620 624 625 + const tldrawColors = [ 626 + "black", 627 + "grey", 628 + "light-violet", 629 + "violet", 630 + "blue", 631 + "light-blue", 632 + "yellow", 633 + "orange", 634 + "green", 635 + "light-green", 636 + "light-red", 637 + "red", 638 + "white", 639 + ] as const; 640 + type TldrawColor = (typeof tldrawColors)[number]; 641 + 642 + const tldrawColorMap: Record<TldrawColor, string> = { 643 + black: "#000000", 644 + grey: "#808080", 645 + "light-violet": "#800080", 646 + violet: "#800080", 647 + blue: "#0000FF", 648 + "light-blue": "#0000FF", 649 + yellow: "#FFFF00", 650 + orange: "#FFA500", 651 + green: "#00FF00", 652 + "light-green": "#00FF00", 653 + "light-red": "#FF0000", 654 + red: "#FF0000", 655 + white: "#FFFFFF", 656 + }; 657 + 621 658 function AppearanceProperties() { 622 659 const editor = useEditorContext(); 623 660 const shape = useValue("shape", () => editor.getSelectedShapes()[0], [ ··· 626 663 627 664 if ( 628 665 !shape || 629 - !("size" in shape.props && "fill" in shape.props && "dash" in shape.props) 666 + !( 667 + "size" in shape.props || 668 + "fill" in shape.props || 669 + "dash" in shape.props || 670 + "color" in shape.props 671 + ) 630 672 ) { 631 673 return null; 632 674 } ··· 640 682 </Text> 641 683 </DisclosureTitle> 642 684 <DisclosurePanel> 643 - <Flex direction="column" gap="2"> 644 - <ToggleButtonGroup 645 - variant="separate" 646 - itemsPerRow={4} 647 - selectedKeys={[shape.props.size]} 648 - onSelectionChange={(keys) => { 649 - const newSize = [...keys][0]; 650 - if (newSize) { 651 - editor.updateShape({ 652 - id: shape.id, 653 - type: shape.type, 654 - props: { 655 - size: newSize, 656 - }, 657 - }); 658 - } 659 - }} 660 - > 661 - <Tooltip text="Small"> 662 - <ToggleButton id="s" variant="outline"> 663 - S 664 - </ToggleButton> 665 - </Tooltip> 666 - <Tooltip text="Medium"> 667 - <ToggleButton id="m" variant="outline"> 668 - M 669 - </ToggleButton> 670 - </Tooltip> 671 - <Tooltip text="Large"> 672 - <ToggleButton id="l" variant="outline"> 673 - L 674 - </ToggleButton> 675 - </Tooltip> 676 - <Tooltip text="Solid"> 677 - <ToggleButton id="xl" variant="outline"> 678 - XL 679 - </ToggleButton> 680 - </Tooltip> 681 - </ToggleButtonGroup> 682 - <ToggleButtonGroup 683 - variant="separate" 684 - itemsPerRow={4} 685 - selectedKeys={[shape.props.fill]} 686 - onSelectionChange={(keys) => { 687 - const newFill = [...keys][0]; 688 - if (newFill) { 689 - editor.updateShape({ 690 - id: shape.id, 691 - type: shape.type, 692 - props: { 693 - fill: newFill, 694 - }, 695 - }); 696 - } 697 - }} 698 - > 699 - <Tooltip text="Fill: None"> 700 - <ToggleButton id="none" variant="outline"> 701 - <Blend /> 702 - </ToggleButton> 703 - </Tooltip> 704 - <Tooltip text="Fill: Partial"> 705 - <ToggleButton id="semi" variant="outline"> 706 - <Layers2 /> 707 - </ToggleButton> 708 - </Tooltip> 709 - <Tooltip text="Fill: Solid"> 710 - <ToggleButton id="solid" variant="outline"> 711 - <Layers /> 712 - </ToggleButton> 713 - </Tooltip> 714 - <Tooltip text="Fill: Pattern"> 715 - <ToggleButton id="pattern" variant="outline"> 716 - <SquareAsterisk /> 717 - </ToggleButton> 718 - </Tooltip> 719 - </ToggleButtonGroup> 720 - <ToggleButtonGroup 721 - variant="separate" 722 - itemsPerRow={4} 723 - selectedKeys={[shape.props.dash]} 724 - onSelectionChange={(keys) => { 725 - const newStroke = [...keys][0]; 726 - if (newStroke) { 727 - editor.updateShape({ 728 - id: shape.id, 729 - type: shape.type, 730 - props: { 731 - dash: newStroke, 732 - }, 733 - }); 734 - } 735 - }} 736 - > 737 - <Tooltip text="Stroke: Dashed"> 738 - <ToggleButton id="dashed" variant="outline"> 739 - <PanelBottomDashed /> 740 - </ToggleButton> 741 - </Tooltip> 742 - <Tooltip text="Stroke: Draw"> 743 - <ToggleButton id="draw" variant="outline"> 744 - <Scan /> 745 - </ToggleButton> 746 - </Tooltip> 747 - <Tooltip text="Stroke: Dotted"> 748 - <ToggleButton id="dotted" variant="outline"> 749 - <SquareDashed /> 750 - </ToggleButton> 751 - </Tooltip> 752 - <Tooltip text="Stroke: Solid"> 753 - <ToggleButton id="solid" variant="outline"> 754 - <Square /> 755 - </ToggleButton> 756 - </Tooltip> 757 - </ToggleButtonGroup> 685 + <Flex direction="column" gap="4"> 686 + <Flex direction="column" gap="2"> 687 + {"size" in shape.props && ( 688 + <ToggleButtonGroup 689 + variant="separate" 690 + itemsPerRow={4} 691 + selectedKeys={[shape.props.size]} 692 + onSelectionChange={(keys) => { 693 + const newSize = [...keys][0]; 694 + if (newSize) { 695 + editor.updateShape({ 696 + id: shape.id, 697 + type: shape.type, 698 + props: { 699 + size: newSize, 700 + }, 701 + }); 702 + } 703 + }} 704 + > 705 + <Tooltip text="Small"> 706 + <ToggleButton id="s" variant="outline"> 707 + S 708 + </ToggleButton> 709 + </Tooltip> 710 + <Tooltip text="Medium"> 711 + <ToggleButton id="m" variant="outline"> 712 + M 713 + </ToggleButton> 714 + </Tooltip> 715 + <Tooltip text="Large"> 716 + <ToggleButton id="l" variant="outline"> 717 + L 718 + </ToggleButton> 719 + </Tooltip> 720 + <Tooltip text="Solid"> 721 + <ToggleButton id="xl" variant="outline"> 722 + XL 723 + </ToggleButton> 724 + </Tooltip> 725 + </ToggleButtonGroup> 726 + )} 727 + {"fill" in shape.props && ( 728 + <ToggleButtonGroup 729 + variant="separate" 730 + itemsPerRow={4} 731 + selectedKeys={[shape.props.fill as Key]} 732 + onSelectionChange={(keys) => { 733 + const newFill = [...keys][0]; 734 + if (newFill) { 735 + editor.updateShape({ 736 + id: shape.id, 737 + type: shape.type, 738 + props: { 739 + fill: newFill, 740 + }, 741 + }); 742 + } 743 + }} 744 + > 745 + <Tooltip text="Fill: None"> 746 + <ToggleButton id="none" variant="outline"> 747 + <Blend /> 748 + </ToggleButton> 749 + </Tooltip> 750 + <Tooltip text="Fill: Partial"> 751 + <ToggleButton id="semi" variant="outline"> 752 + <Layers2 /> 753 + </ToggleButton> 754 + </Tooltip> 755 + <Tooltip text="Fill: Solid"> 756 + <ToggleButton id="solid" variant="outline"> 757 + <Layers /> 758 + </ToggleButton> 759 + </Tooltip> 760 + <Tooltip text="Fill: Pattern"> 761 + <ToggleButton id="pattern" variant="outline"> 762 + <SquareAsterisk /> 763 + </ToggleButton> 764 + </Tooltip> 765 + </ToggleButtonGroup> 766 + )} 767 + {"dash" in shape.props && ( 768 + <ToggleButtonGroup 769 + variant="separate" 770 + itemsPerRow={4} 771 + selectedKeys={[shape.props.dash as Key]} 772 + onSelectionChange={(keys) => { 773 + const newStroke = [...keys][0]; 774 + if (newStroke) { 775 + editor.updateShape({ 776 + id: shape.id, 777 + type: shape.type, 778 + props: { 779 + dash: newStroke, 780 + }, 781 + }); 782 + } 783 + }} 784 + > 785 + <Tooltip text="Stroke: Dashed"> 786 + <ToggleButton id="dashed" variant="outline"> 787 + <PanelBottomDashed /> 788 + </ToggleButton> 789 + </Tooltip> 790 + <Tooltip text="Stroke: Draw"> 791 + <ToggleButton id="draw" variant="outline"> 792 + <Scan /> 793 + </ToggleButton> 794 + </Tooltip> 795 + <Tooltip text="Stroke: Dotted"> 796 + <ToggleButton id="dotted" variant="outline"> 797 + <SquareDashed /> 798 + </ToggleButton> 799 + </Tooltip> 800 + <Tooltip text="Stroke: Solid"> 801 + <ToggleButton id="solid" variant="outline"> 802 + <Square /> 803 + </ToggleButton> 804 + </Tooltip> 805 + </ToggleButtonGroup> 806 + )} 807 + </Flex> 808 + {"color" in shape.props && ( 809 + <ColorSwatchPicker 810 + value={tldrawColorMap[shape.props.color as TldrawColor]} 811 + onChange={(color) => { 812 + const tldrawColor = Object.keys(tldrawColorMap).find( 813 + (key) => 814 + tldrawColorMap[key as TldrawColor] === 815 + color.toString("hex"), 816 + ); 817 + 818 + if (tldrawColor) { 819 + editor.updateShape({ 820 + id: shape.id, 821 + type: shape.type, 822 + props: { color: tldrawColor as TldrawColor }, 823 + }); 824 + } 825 + }} 826 + > 827 + {tldrawColors.map((color) => ( 828 + <ColorSwatchPickerItem 829 + key={color} 830 + color={tldrawColorMap[color]} 831 + /> 832 + ))} 833 + </ColorSwatchPicker> 834 + )} 758 835 </Flex> 759 836 </DisclosurePanel> 760 837 </Disclosure> ··· 803 880 }, 804 881 [editor], 805 882 ); 883 + const labelColor = useValue( 884 + "labelColor", 885 + () => { 886 + if (!shapeId) return null; 887 + const shape = editor.getShape(shapeId); 888 + if (!shape || !("labelColor" in shape.props)) return null; 889 + return shape.props.labelColor; 890 + }, 891 + [editor], 892 + ); 806 893 807 - if (!fontFamily || !shapeId || !shapeType) { 894 + if (!fontFamily || !shapeId || !shapeType || !labelColor) { 808 895 return null; 809 896 } 810 897 ··· 817 904 </Text> 818 905 </DisclosureTitle> 819 906 <DisclosurePanel> 820 - <Flex direction="column" gap="2"> 821 - <Select 822 - label="Family" 823 - placeholder="Select font family" 824 - value={fontFamily} 825 - onChange={(value) => { 826 - editor.updateShape({ 827 - id: shapeId, 828 - type: shapeType, 829 - props: { font: value }, 830 - }); 907 + <Flex direction="column" gap="4"> 908 + <Flex direction="column" gap="2"> 909 + <Select 910 + label="Family" 911 + placeholder="Select font family" 912 + value={fontFamily} 913 + onChange={(value) => { 914 + editor.updateShape({ 915 + id: shapeId, 916 + type: shapeType, 917 + props: { font: value }, 918 + }); 919 + }} 920 + > 921 + <SelectItem id="draw">Draw</SelectItem> 922 + <SelectItem id="sans">Sans</SelectItem> 923 + <SelectItem id="serif">Serif</SelectItem> 924 + <SelectItem id="mono">Mono</SelectItem> 925 + </Select> 926 + {align && ( 927 + <ToggleButtonGroup 928 + variant="separate" 929 + itemsPerRow={4} 930 + selectedKeys={[align]} 931 + onSelectionChange={(keys) => { 932 + const newAlign = [...keys][0]; 933 + if (newAlign) { 934 + editor.updateShape({ 935 + id: shapeId, 936 + type: shapeType, 937 + props: { align: newAlign }, 938 + }); 939 + } 940 + }} 941 + > 942 + <Tooltip text="Align: Start"> 943 + <ToggleButton id="start" variant="outline"> 944 + <TextAlignStart /> 945 + </ToggleButton> 946 + </Tooltip> 947 + <Tooltip text="Align: Middle"> 948 + <ToggleButton id="middle" variant="outline"> 949 + <TextAlignCenter /> 950 + </ToggleButton> 951 + </Tooltip> 952 + <Tooltip text="Align: End"> 953 + <ToggleButton id="end" variant="outline"> 954 + <TextAlignEnd /> 955 + </ToggleButton> 956 + </Tooltip> 957 + </ToggleButtonGroup> 958 + )} 959 + {verticalAlign && ( 960 + <ToggleButtonGroup 961 + variant="separate" 962 + itemsPerRow={4} 963 + selectedKeys={[verticalAlign]} 964 + onSelectionChange={(keys) => { 965 + const newAlign = [...keys][0]; 966 + if (newAlign) { 967 + editor.updateShape({ 968 + id: shapeId, 969 + type: shapeType, 970 + props: { verticalAlign: newAlign }, 971 + }); 972 + } 973 + }} 974 + > 975 + <Tooltip text="Vertical Align: Start"> 976 + <ToggleButton id="start" variant="outline"> 977 + <AlignStartHorizontal /> 978 + </ToggleButton> 979 + </Tooltip> 980 + <Tooltip text="Vertical Align: Middle"> 981 + <ToggleButton id="middle" variant="outline"> 982 + <AlignCenterHorizontal /> 983 + </ToggleButton> 984 + </Tooltip> 985 + <Tooltip text="Vertical Align: End"> 986 + <ToggleButton id="end" variant="outline"> 987 + <AlignEndHorizontal /> 988 + </ToggleButton> 989 + </Tooltip> 990 + </ToggleButtonGroup> 991 + )} 992 + </Flex> 993 + 994 + <Separator /> 995 + <ColorSwatchPicker 996 + value={tldrawColorMap[labelColor as TldrawColor]} 997 + onChange={(color) => { 998 + const tldrawColor = Object.keys(tldrawColorMap).find( 999 + (key) => 1000 + tldrawColorMap[key as TldrawColor] === 1001 + color.toString("hex"), 1002 + ); 1003 + 1004 + if (tldrawColor) { 1005 + editor.updateShape({ 1006 + id: shapeId, 1007 + type: shapeType, 1008 + props: { labelColor: tldrawColor as TldrawColor }, 1009 + }); 1010 + } 831 1011 }} 832 1012 > 833 - <SelectItem id="draw">Draw</SelectItem> 834 - <SelectItem id="sans">Sans</SelectItem> 835 - <SelectItem id="serif">Serif</SelectItem> 836 - <SelectItem id="mono">Mono</SelectItem> 837 - </Select> 838 - {align && ( 839 - <ToggleButtonGroup 840 - variant="separate" 841 - itemsPerRow={4} 842 - selectedKeys={[align]} 843 - onSelectionChange={(keys) => { 844 - const newAlign = [...keys][0]; 845 - if (newAlign) { 846 - editor.updateShape({ 847 - id: shapeId, 848 - type: shapeType, 849 - props: { align: newAlign }, 850 - }); 851 - } 852 - }} 853 - > 854 - <Tooltip text="Align: Start"> 855 - <ToggleButton id="start" variant="outline"> 856 - <TextAlignStart /> 857 - </ToggleButton> 858 - </Tooltip> 859 - <Tooltip text="Align: Middle"> 860 - <ToggleButton id="middle" variant="outline"> 861 - <TextAlignCenter /> 862 - </ToggleButton> 863 - </Tooltip> 864 - <Tooltip text="Align: End"> 865 - <ToggleButton id="end" variant="outline"> 866 - <TextAlignEnd /> 867 - </ToggleButton> 868 - </Tooltip> 869 - </ToggleButtonGroup> 870 - )} 871 - {verticalAlign && ( 872 - <ToggleButtonGroup 873 - variant="separate" 874 - itemsPerRow={4} 875 - selectedKeys={[verticalAlign]} 876 - onSelectionChange={(keys) => { 877 - const newAlign = [...keys][0]; 878 - if (newAlign) { 879 - editor.updateShape({ 880 - id: shapeId, 881 - type: shapeType, 882 - props: { verticalAlign: newAlign }, 883 - }); 884 - } 885 - }} 886 - > 887 - <Tooltip text="Vertical Align: Start"> 888 - <ToggleButton id="start" variant="outline"> 889 - <AlignStartHorizontal /> 890 - </ToggleButton> 891 - </Tooltip> 892 - <Tooltip text="Vertical Align: Middle"> 893 - <ToggleButton id="middle" variant="outline"> 894 - <AlignCenterHorizontal /> 895 - </ToggleButton> 896 - </Tooltip> 897 - <Tooltip text="Vertical Align: End"> 898 - <ToggleButton id="end" variant="outline"> 899 - <AlignEndHorizontal /> 900 - </ToggleButton> 901 - </Tooltip> 902 - </ToggleButtonGroup> 903 - )} 1013 + {tldrawColors.map((color) => ( 1014 + <ColorSwatchPickerItem 1015 + key={color} 1016 + color={tldrawColorMap[color]} 1017 + /> 1018 + ))} 1019 + </ColorSwatchPicker> 904 1020 </Flex> 905 1021 </DisclosurePanel> 906 1022 </Disclosure>