@usefui/components 1.6.0 → 1.7.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 +12 -0
- package/dist/index.d.mts +380 -52
- package/dist/index.d.ts +380 -52
- package/dist/index.js +2532 -511
- package/dist/index.mjs +2518 -508
- package/package.json +3 -3
- package/src/__tests__/Avatar.test.tsx +55 -55
- package/src/accordion/Accordion.stories.tsx +6 -4
- package/src/accordion/index.tsx +1 -2
- package/src/avatar/Avatar.stories.tsx +37 -7
- package/src/avatar/index.tsx +90 -19
- package/src/avatar/styles/index.ts +58 -12
- package/src/badge/Badge.stories.tsx +27 -5
- package/src/badge/index.tsx +21 -13
- package/src/badge/styles/index.ts +69 -40
- package/src/button/Button.stories.tsx +40 -27
- package/src/button/index.tsx +13 -9
- package/src/button/styles/index.ts +308 -47
- package/src/card/index.tsx +2 -4
- package/src/checkbox/Checkbox.stories.tsx +72 -33
- package/src/checkbox/index.tsx +8 -6
- package/src/checkbox/styles/index.ts +239 -19
- package/src/collapsible/Collapsible.stories.tsx +6 -4
- package/src/dialog/Dialog.stories.tsx +173 -31
- package/src/dialog/styles/index.ts +13 -8
- package/src/dropdown/Dropdown.stories.tsx +61 -23
- package/src/dropdown/index.tsx +42 -31
- package/src/dropdown/styles/index.ts +30 -19
- package/src/field/Field.stories.tsx +183 -24
- package/src/field/index.tsx +930 -13
- package/src/field/styles/index.ts +246 -14
- package/src/field/types/index.ts +31 -0
- package/src/field/utils/index.ts +201 -0
- package/src/index.ts +2 -1
- package/src/message-bubble/MessageBubble.stories.tsx +59 -12
- package/src/message-bubble/index.tsx +22 -4
- package/src/message-bubble/styles/index.ts +4 -7
- package/src/otp-field/OTPField.stories.tsx +22 -24
- package/src/otp-field/index.tsx +9 -0
- package/src/otp-field/styles/index.ts +114 -16
- package/src/otp-field/types/index.ts +9 -1
- package/src/overlay/styles/index.ts +1 -0
- package/src/ruler/Ruler.stories.tsx +43 -0
- package/src/ruler/constants/index.ts +3 -0
- package/src/ruler/hooks/index.tsx +53 -0
- package/src/ruler/index.tsx +239 -0
- package/src/ruler/styles/index.tsx +154 -0
- package/src/ruler/types/index.ts +17 -0
- package/src/select/Select.stories.tsx +91 -0
- package/src/select/hooks/index.tsx +71 -0
- package/src/select/index.tsx +331 -0
- package/src/select/styles/index.tsx +156 -0
- package/src/shimmer/Shimmer.stories.tsx +6 -4
- package/src/skeleton/index.tsx +7 -6
- package/src/spinner/Spinner.stories.tsx +29 -4
- package/src/spinner/index.tsx +16 -6
- package/src/spinner/styles/index.ts +41 -22
- package/src/switch/Switch.stories.tsx +46 -17
- package/src/switch/index.tsx +5 -8
- package/src/switch/styles/index.ts +45 -45
- package/src/tabs/Tabs.stories.tsx +43 -15
- package/src/text-area/Textarea.stories.tsx +45 -8
- package/src/text-area/index.tsx +9 -6
- package/src/text-area/styles/index.ts +1 -1
- package/src/toggle/Toggle.stories.tsx +6 -4
- package/src/tree/Tree.stories.tsx +6 -4
- package/src/privacy-field/PrivacyField.stories.tsx +0 -29
- package/src/privacy-field/index.tsx +0 -56
- package/src/privacy-field/styles/index.ts +0 -17
|
@@ -10,7 +10,17 @@ import {
|
|
|
10
10
|
MessageBubbleMetaWrapper,
|
|
11
11
|
} from "./styles";
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
ComponentShapeEnum,
|
|
15
|
+
ComponentSizeEnum,
|
|
16
|
+
ComponentVariantEnum,
|
|
17
|
+
IComponentShape,
|
|
18
|
+
IComponentSize,
|
|
19
|
+
IComponentStyling,
|
|
20
|
+
IReactChildren,
|
|
21
|
+
TComponentVariant,
|
|
22
|
+
TComponentVariantExtended,
|
|
23
|
+
} from "../../../../types";
|
|
14
24
|
|
|
15
25
|
export type MessageBubbleSide = "left" | "right";
|
|
16
26
|
|
|
@@ -24,7 +34,12 @@ export interface IMessageBubbleProperties
|
|
|
24
34
|
}
|
|
25
35
|
|
|
26
36
|
export interface IMessageBubbleContentProperties
|
|
27
|
-
extends
|
|
37
|
+
extends
|
|
38
|
+
IComponentStyling,
|
|
39
|
+
IComponentShape,
|
|
40
|
+
IComponentSize,
|
|
41
|
+
React.HTMLAttributes<HTMLDivElement> {
|
|
42
|
+
variant?: TComponentVariant | TComponentVariantExtended;
|
|
28
43
|
children: string;
|
|
29
44
|
}
|
|
30
45
|
|
|
@@ -88,14 +103,16 @@ MessageBubble.displayName = "MessageBubble";
|
|
|
88
103
|
* @returns {ReactElement} The MessageBubble.Content component.
|
|
89
104
|
*/
|
|
90
105
|
const MessageBubbleContent = (props: IMessageBubbleContentProperties) => {
|
|
91
|
-
const { children, raw, ...restProps } = props;
|
|
106
|
+
const { sizing, shape, variant, children, raw, ...restProps } = props;
|
|
92
107
|
const { id, states } = useMessageBubble();
|
|
93
108
|
|
|
94
109
|
return (
|
|
95
110
|
<MessageBubbleBadge
|
|
96
|
-
variant="secondary"
|
|
97
111
|
data-raw={Boolean(raw)}
|
|
98
112
|
data-side={states?.side}
|
|
113
|
+
variant={variant ?? ComponentVariantEnum.Border}
|
|
114
|
+
shape={shape ?? ComponentShapeEnum.Smooth}
|
|
115
|
+
sizing={sizing ?? ComponentSizeEnum.Medium}
|
|
99
116
|
aria-label={`message-bubble-content-${id}`}
|
|
100
117
|
{...restProps}
|
|
101
118
|
>
|
|
@@ -133,6 +150,7 @@ const MessageBubbleMeta = (props: IMessageBubbleMetaProperties) => {
|
|
|
133
150
|
data-raw={Boolean(raw)}
|
|
134
151
|
data-side={states?.side}
|
|
135
152
|
aria-label={`message-bubble-meta-${states?.side}`}
|
|
153
|
+
className="fs-small-60 opacity-default-60"
|
|
136
154
|
{...restProps}
|
|
137
155
|
>
|
|
138
156
|
{formattedDate}
|
|
@@ -21,27 +21,24 @@ export const MessageBubbleBadge: React.FC<IBadgeProperties> = styled(Badge)`
|
|
|
21
21
|
width: 100%;
|
|
22
22
|
justify-self: flex-end;
|
|
23
23
|
padding: var(--measurement-medium-30) var(--measurement-medium-50) !important;
|
|
24
|
-
border-radius: var(--measurement-medium-60) !important;
|
|
25
24
|
|
|
26
25
|
&[data-side="left"] {
|
|
27
|
-
|
|
28
|
-
border-bottom-left-radius: 0 !important;
|
|
26
|
+
border-top-left-radius: 0 !important;
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
&[data-side="right"] {
|
|
32
|
-
|
|
33
|
-
border-bottom-right-radius: 0 !important;
|
|
30
|
+
border-top-right-radius: 0 !important;
|
|
34
31
|
}
|
|
35
32
|
`;
|
|
36
33
|
|
|
37
34
|
export const MessageBubbleContentWrapper = styled.div`
|
|
38
|
-
line-height: 1.
|
|
35
|
+
line-height: 1.3;
|
|
39
36
|
font-weight: 500;
|
|
40
37
|
word-break: keep-all;
|
|
41
38
|
width: 100%;
|
|
42
39
|
|
|
43
40
|
* {
|
|
44
|
-
font-size:
|
|
41
|
+
font-size: inherit !important;
|
|
45
42
|
}
|
|
46
43
|
`;
|
|
47
44
|
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
-
|
|
4
2
|
import { Field, OTPField, Page } from "..";
|
|
5
3
|
|
|
6
4
|
const meta = {
|
|
@@ -8,13 +6,17 @@ const meta = {
|
|
|
8
6
|
component: OTPField,
|
|
9
7
|
tags: ["autodocs"],
|
|
10
8
|
decorators: [
|
|
11
|
-
(Story) => (
|
|
12
|
-
<
|
|
13
|
-
<
|
|
14
|
-
|
|
9
|
+
(Story: any) => (
|
|
10
|
+
<Page>
|
|
11
|
+
<Page.Content className="p-medium-30">
|
|
12
|
+
<div className="flex flex-column align-center justify-center h-100">
|
|
13
|
+
<Story />
|
|
14
|
+
</div>
|
|
15
|
+
</Page.Content>
|
|
16
|
+
</Page>
|
|
15
17
|
),
|
|
16
18
|
],
|
|
17
|
-
}
|
|
19
|
+
};
|
|
18
20
|
export default meta;
|
|
19
21
|
|
|
20
22
|
export const Default = {
|
|
@@ -27,24 +29,20 @@ export const Default = {
|
|
|
27
29
|
setValue(value.trim());
|
|
28
30
|
}, []);
|
|
29
31
|
return (
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<OTPField.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
</OTPField.Group>
|
|
41
|
-
</OTPField>
|
|
32
|
+
<form aria-label="story-form" style={{ width: 325 }}>
|
|
33
|
+
<Field.Wrapper className="w-100">
|
|
34
|
+
<Field.Label>Confirmation code</Field.Label>
|
|
35
|
+
<OTPField length={6} onComplete={handleComplete}>
|
|
36
|
+
<OTPField.Group>
|
|
37
|
+
{Array.from({ length: 6 }).map((_, index) => (
|
|
38
|
+
<OTPField.Slot key={index} index={index} />
|
|
39
|
+
))}
|
|
40
|
+
</OTPField.Group>
|
|
41
|
+
</OTPField>
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</Page.Content>
|
|
47
|
-
</Page>
|
|
43
|
+
{value}
|
|
44
|
+
</Field.Wrapper>
|
|
45
|
+
</form>
|
|
48
46
|
);
|
|
49
47
|
},
|
|
50
48
|
};
|
package/src/otp-field/index.tsx
CHANGED
|
@@ -6,6 +6,11 @@ import { useOTPField, OTPFieldContext } from "./hooks";
|
|
|
6
6
|
import { OTPCell } from "./styles";
|
|
7
7
|
|
|
8
8
|
import type { OTPFieldProps, OTPFieldSlotProps } from "./types";
|
|
9
|
+
import {
|
|
10
|
+
ComponentShapeEnum,
|
|
11
|
+
ComponentSizeEnum,
|
|
12
|
+
ComponentVariantEnum,
|
|
13
|
+
} from "../../../../types";
|
|
9
14
|
|
|
10
15
|
export interface IOTPFieldComposition {
|
|
11
16
|
Slot: typeof OTPFieldSlot;
|
|
@@ -191,6 +196,8 @@ OTPFieldGroup.displayName = "OTPField.Group";
|
|
|
191
196
|
*/
|
|
192
197
|
const OTPFieldSlot = ({
|
|
193
198
|
index,
|
|
199
|
+
shape,
|
|
200
|
+
raw,
|
|
194
201
|
...props
|
|
195
202
|
}: OTPFieldSlotProps & React.InputHTMLAttributes<HTMLInputElement>) => {
|
|
196
203
|
const context = useOTPField();
|
|
@@ -215,6 +222,8 @@ const OTPFieldSlot = ({
|
|
|
215
222
|
type="text"
|
|
216
223
|
data-testid="otp-field-slot"
|
|
217
224
|
data-active={activeIndex === index}
|
|
225
|
+
data-shape={shape ?? ComponentShapeEnum.Smooth}
|
|
226
|
+
data-raw={Boolean(raw)}
|
|
218
227
|
autoComplete="one-time-code"
|
|
219
228
|
maxLength={1}
|
|
220
229
|
value={otp[index] || ""}
|
|
@@ -1,33 +1,131 @@
|
|
|
1
|
-
import styled from "styled-components";
|
|
1
|
+
import styled, { css } from "styled-components";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const OTPShapeStyles = css`
|
|
4
|
+
&[data-shape="square"] {
|
|
5
|
+
border-radius: 0;
|
|
6
|
+
}
|
|
7
|
+
&[data-shape="smooth"] {
|
|
8
|
+
border-radius: var(--measurement-medium-20);
|
|
9
|
+
}
|
|
10
|
+
&[data-shape="round"] {
|
|
11
|
+
border-radius: var(--measurement-large-90);
|
|
12
|
+
padding-left: var(--measurement-medium-50) !important;
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
const OTPCellDefaultStyles = css`
|
|
17
|
+
outline: none;
|
|
18
|
+
cursor: text;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
text-align: center;
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
|
|
25
|
+
font-size: var(--fontsize-medium-20);
|
|
26
|
+
|
|
27
|
+
padding: 0 var(--measurement-medium-30);
|
|
4
28
|
width: var(--measurement-medium-90);
|
|
5
29
|
height: var(--measurement-medium-90);
|
|
6
|
-
border: var(--measurement-small-10) solid var(--font-color-alpha-10);
|
|
7
30
|
|
|
8
|
-
|
|
31
|
+
line-height: 1;
|
|
32
|
+
letter-spacing: calc(
|
|
33
|
+
var(--fontsize-small-10) - ((var(--fontsize-small-10) * 1.066))
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
border: var(--measurement-small-10) solid transparent;
|
|
37
|
+
|
|
9
38
|
backdrop-filter: blur(var(--measurement-small-10));
|
|
39
|
+
color: var(--font-color-alpha-60);
|
|
10
40
|
|
|
11
|
-
|
|
12
|
-
font-size: var(--fontsize-medium-10);
|
|
13
|
-
font-weight: 500;
|
|
41
|
+
transition: all ease-in-out 0.2s;
|
|
14
42
|
|
|
15
|
-
|
|
16
|
-
|
|
43
|
+
svg,
|
|
44
|
+
span,
|
|
45
|
+
img {
|
|
46
|
+
opacity: 0.6;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&:hover,
|
|
50
|
+
&:focus,
|
|
51
|
+
&:active,
|
|
52
|
+
&:focus-within,
|
|
53
|
+
&:has(:active) {
|
|
54
|
+
color: var(--font-color);
|
|
55
|
+
svg,
|
|
56
|
+
span,
|
|
57
|
+
img {
|
|
58
|
+
opacity: 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
&::placeholder {
|
|
63
|
+
color: var(--font-color-alpha-30);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&:disabled,
|
|
67
|
+
&:has(:disabled) {
|
|
68
|
+
cursor: not-allowed;
|
|
69
|
+
opacity: 0.6;
|
|
70
|
+
}
|
|
17
71
|
|
|
18
72
|
background-color: transparent;
|
|
19
|
-
|
|
20
|
-
outline: none;
|
|
73
|
+
border-color: var(--font-color-alpha-10);
|
|
21
74
|
|
|
22
|
-
&:
|
|
23
|
-
|
|
75
|
+
&:hover,
|
|
76
|
+
&:focus,
|
|
77
|
+
&:active,
|
|
78
|
+
&:focus-within,
|
|
79
|
+
&:has(:hover),
|
|
80
|
+
&:has(:active) {
|
|
81
|
+
border-color: var(--font-color-alpha-20);
|
|
24
82
|
}
|
|
25
83
|
|
|
26
|
-
&:
|
|
84
|
+
&:focus,
|
|
85
|
+
&:active,
|
|
86
|
+
&:focus-within,
|
|
87
|
+
&:has(:active) {
|
|
88
|
+
box-shadow: 0 0 0 var(--measurement-small-30) var(--alpha-accent-30);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
background-color: transparent;
|
|
92
|
+
border-color: var(--font-color-alpha-10);
|
|
93
|
+
|
|
94
|
+
&:hover,
|
|
95
|
+
&:focus,
|
|
96
|
+
&:active,
|
|
97
|
+
&:focus-within,
|
|
98
|
+
&:has(:hover),
|
|
99
|
+
&:has(:active) {
|
|
27
100
|
border-color: var(--font-color-alpha-20);
|
|
28
101
|
}
|
|
29
102
|
|
|
30
|
-
|
|
31
|
-
|
|
103
|
+
&:focus,
|
|
104
|
+
&:active,
|
|
105
|
+
&:focus-within,
|
|
106
|
+
&:has(:active) {
|
|
107
|
+
box-shadow: 0 0 0 var(--measurement-small-30) var(--font-color-alpha-10);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
&[data-error="true"] {
|
|
111
|
+
color: var(--color-red);
|
|
112
|
+
border-color: var(--alpha-red-10);
|
|
113
|
+
|
|
114
|
+
&:hover,
|
|
115
|
+
&:focus,
|
|
116
|
+
&:active,
|
|
117
|
+
&:focus-within,
|
|
118
|
+
&:has(:hover),
|
|
119
|
+
&:has(:active) {
|
|
120
|
+
background-color: var(--alpha-red-10);
|
|
121
|
+
box-shadow: 0 0 0 var(--measurement-small-30) var(--alpha-red-10);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
`;
|
|
125
|
+
|
|
126
|
+
export const OTPCell = styled.input`
|
|
127
|
+
&[data-raw="false"] {
|
|
128
|
+
${OTPCellDefaultStyles}
|
|
129
|
+
${OTPShapeStyles}
|
|
32
130
|
}
|
|
33
131
|
`;
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IComponentSize,
|
|
3
|
+
IComponentVariant,
|
|
4
|
+
IComponentShape,
|
|
5
|
+
IComponentStyling,
|
|
6
|
+
} from "../../../../../types";
|
|
7
|
+
|
|
1
8
|
export interface OTPFieldContextType {
|
|
2
9
|
otp: string[];
|
|
3
10
|
inputRefs: React.MutableRefObject<(HTMLInputElement | null)[]>;
|
|
@@ -18,6 +25,7 @@ export interface OTPFieldProps {
|
|
|
18
25
|
onComplete?: (value: string) => void;
|
|
19
26
|
}
|
|
20
27
|
|
|
21
|
-
export interface OTPFieldSlotProps
|
|
28
|
+
export interface OTPFieldSlotProps
|
|
29
|
+
extends IComponentVariant, IComponentStyling, IComponentShape {
|
|
22
30
|
index: number;
|
|
23
31
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Page } from "../";
|
|
4
|
+
import { Ruler } from "./index";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* RulerCanvas renders a canvas area with horizontal and vertical rulers,
|
|
8
|
+
* allowing users to create and drag guides for precise alignment.
|
|
9
|
+
*/
|
|
10
|
+
const meta = {
|
|
11
|
+
title: "Components/Ruler",
|
|
12
|
+
component: Ruler,
|
|
13
|
+
tags: ["autodocs"],
|
|
14
|
+
} satisfies Meta<typeof Ruler>;
|
|
15
|
+
export default meta;
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj<typeof meta>;
|
|
18
|
+
|
|
19
|
+
export const Default: Story = {
|
|
20
|
+
args: {},
|
|
21
|
+
render: ({ ...args }) => (
|
|
22
|
+
<Page>
|
|
23
|
+
<Page.Content>
|
|
24
|
+
<Ruler.Root>
|
|
25
|
+
<Ruler>
|
|
26
|
+
<Ruler.Corner />
|
|
27
|
+
<Ruler.Row orientation="horizontal" />
|
|
28
|
+
<Ruler.Row orientation="vertical" />
|
|
29
|
+
<Ruler.Canvas>
|
|
30
|
+
<Ruler.Lines />
|
|
31
|
+
<div
|
|
32
|
+
className="h-100 w-100 flex align-center justify-center"
|
|
33
|
+
style={{ background: "var(--background-color)" }}
|
|
34
|
+
>
|
|
35
|
+
<p className="fs-medium-20">Canvas Content</p>
|
|
36
|
+
</div>
|
|
37
|
+
</Ruler.Canvas>
|
|
38
|
+
</Ruler>
|
|
39
|
+
</Ruler.Root>
|
|
40
|
+
</Page.Content>
|
|
41
|
+
</Page>
|
|
42
|
+
),
|
|
43
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import type { RulerContextType, Guide } from "../types";
|
|
5
|
+
|
|
6
|
+
const RulerContext = React.createContext<RulerContextType | null>(null);
|
|
7
|
+
|
|
8
|
+
export function useRuler() {
|
|
9
|
+
const context = React.useContext(RulerContext);
|
|
10
|
+
if (!context) throw new Error("useRuler must be used within RulerProvider");
|
|
11
|
+
return context;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function RulerProvider({ children }: { children: React.ReactNode }) {
|
|
15
|
+
const [guides, setGuides] = React.useState<Guide[]>([]);
|
|
16
|
+
const [activeGuide, setActiveGuide] = React.useState<Guide | null>(null);
|
|
17
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
18
|
+
const canvasRef = React.useRef<HTMLDivElement>(null);
|
|
19
|
+
|
|
20
|
+
const addGuide = React.useCallback((guide: Omit<Guide, "id">) => {
|
|
21
|
+
const newGuide = { ...guide, id: crypto.randomUUID() };
|
|
22
|
+
setGuides((prev) => [...prev, newGuide]);
|
|
23
|
+
return newGuide;
|
|
24
|
+
}, []);
|
|
25
|
+
|
|
26
|
+
const updateGuide = React.useCallback((id: string, position: number) => {
|
|
27
|
+
setGuides((prev) =>
|
|
28
|
+
prev.map((g) => (g.id === id ? { ...g, position } : g)),
|
|
29
|
+
);
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
const removeGuide = React.useCallback((id: string) => {
|
|
33
|
+
setGuides((prev) => prev.filter((g) => g.id !== id));
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<RulerContext.Provider
|
|
38
|
+
value={{
|
|
39
|
+
guides,
|
|
40
|
+
addGuide,
|
|
41
|
+
updateGuide,
|
|
42
|
+
removeGuide,
|
|
43
|
+
activeGuide,
|
|
44
|
+
setActiveGuide,
|
|
45
|
+
isDragging,
|
|
46
|
+
setIsDragging,
|
|
47
|
+
canvasRef,
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
</RulerContext.Provider>
|
|
52
|
+
);
|
|
53
|
+
}
|