@reactberry/system 2.0.0-beta

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 (165) hide show
  1. package/README.md +48 -0
  2. package/package.json +74 -0
  3. package/src/blocks/Accordion/index.tsx +158 -0
  4. package/src/blocks/AnimatedCarousel/index.tsx +188 -0
  5. package/src/blocks/AppleGlow/index.tsx +144 -0
  6. package/src/blocks/Avatar/index.tsx +167 -0
  7. package/src/blocks/Await/index.tsx +45 -0
  8. package/src/blocks/Cards/AnimatedCard/index.tsx +175 -0
  9. package/src/blocks/Cards/FluorescentCard/index.tsx +180 -0
  10. package/src/blocks/Cards/InfoCard/index.tsx +206 -0
  11. package/src/blocks/Cards/TickerCard/index.tsx +125 -0
  12. package/src/blocks/Carousel/index.tsx +216 -0
  13. package/src/blocks/Checkbox/index.tsx +101 -0
  14. package/src/blocks/Collection/index.tsx +59 -0
  15. package/src/blocks/Container/index.tsx +55 -0
  16. package/src/blocks/Controls/Control.tsx +67 -0
  17. package/src/blocks/Controls/index.tsx +11 -0
  18. package/src/blocks/CyclingNumber/index.tsx +78 -0
  19. package/src/blocks/DisplaySet/index.tsx +42 -0
  20. package/src/blocks/Divider/index.tsx +14 -0
  21. package/src/blocks/Draggable/index.tsx +266 -0
  22. package/src/blocks/Drawer/index.tsx +136 -0
  23. package/src/blocks/DynamicIsland/DynamicIsland.tsx +89 -0
  24. package/src/blocks/DynamicIsland/index.tsx +2 -0
  25. package/src/blocks/Fader/index.tsx +145 -0
  26. package/src/blocks/FamilyDrawer/README.md +116 -0
  27. package/src/blocks/FamilyDrawer/example.tsx +108 -0
  28. package/src/blocks/FamilyDrawer/index.tsx +119 -0
  29. package/src/blocks/FamilyDrawer/views/DefaultView.tsx +93 -0
  30. package/src/blocks/FamilyDrawer/views/KeyView.tsx +129 -0
  31. package/src/blocks/FamilyDrawer/views/PhraseView.tsx +129 -0
  32. package/src/blocks/FamilyDrawer/views/RemoveView.tsx +81 -0
  33. package/src/blocks/FieldSet/index.tsx +173 -0
  34. package/src/blocks/Filesystem/index.tsx +198 -0
  35. package/src/blocks/Gallery/Carousel/index.tsx +257 -0
  36. package/src/blocks/Gallery/Modal/index.tsx +83 -0
  37. package/src/blocks/Gallery/index.tsx +57 -0
  38. package/src/blocks/Gallery/utils/animationVariants.ts +18 -0
  39. package/src/blocks/Gallery/utils/aspectRatio.ts +14 -0
  40. package/src/blocks/Gallery/utils/downloadPhoto.ts +24 -0
  41. package/src/blocks/Gallery/utils/range.ts +11 -0
  42. package/src/blocks/GradientMesh/index.tsx +106 -0
  43. package/src/blocks/Group/index.tsx +152 -0
  44. package/src/blocks/Heading/index.tsx +111 -0
  45. package/src/blocks/HorizontalScroller/index.tsx +135 -0
  46. package/src/blocks/Icon/index.tsx +45 -0
  47. package/src/blocks/Indicator/index.tsx +27 -0
  48. package/src/blocks/InlineEditor/index.tsx +216 -0
  49. package/src/blocks/List/index.tsx +657 -0
  50. package/src/blocks/Main/index.tsx +17 -0
  51. package/src/blocks/Marquee/index.tsx +116 -0
  52. package/src/blocks/MaskedField/index.tsx +199 -0
  53. package/src/blocks/Menu/MenuContent.tsx +246 -0
  54. package/src/blocks/Menu/MenuContext.tsx +34 -0
  55. package/src/blocks/Menu/MenuItem.tsx +104 -0
  56. package/src/blocks/Menu/index.tsx +60 -0
  57. package/src/blocks/Modal/index.tsx +268 -0
  58. package/src/blocks/MorphingPopover/index.tsx +294 -0
  59. package/src/blocks/Overlay/Backdrop.tsx +48 -0
  60. package/src/blocks/Overlay/OverscrollGuard.tsx +36 -0
  61. package/src/blocks/Overlay/index.ts +2 -0
  62. package/src/blocks/Parallax/index.tsx +117 -0
  63. package/src/blocks/ParallaxSection/index.tsx +61 -0
  64. package/src/blocks/Placeholder/index.tsx +48 -0
  65. package/src/blocks/Popover/index.tsx +402 -0
  66. package/src/blocks/Progress/getProgressColor.ts +61 -0
  67. package/src/blocks/Progress/index.tsx +179 -0
  68. package/src/blocks/ProgressiveBlur/index.tsx +75 -0
  69. package/src/blocks/README.md +15 -0
  70. package/src/blocks/RenderAsset/index.tsx +18 -0
  71. package/src/blocks/ScrollContainer/index.tsx +93 -0
  72. package/src/blocks/ShinyText/index.tsx +72 -0
  73. package/src/blocks/Skeleton/index.tsx +71 -0
  74. package/src/blocks/Slider/SliderControls.tsx +119 -0
  75. package/src/blocks/Slider/index.tsx +140 -0
  76. package/src/blocks/Slider/useSlider.ts +126 -0
  77. package/src/blocks/Slideshow/index.tsx +177 -0
  78. package/src/blocks/Spotlight/index.tsx +144 -0
  79. package/src/blocks/Steps/StepIndicator.tsx +149 -0
  80. package/src/blocks/Steps/StepProgress.tsx +164 -0
  81. package/src/blocks/Steps/Steps.tsx +197 -0
  82. package/src/blocks/Steps/StepsNav.tsx +30 -0
  83. package/src/blocks/Steps/StepsTracker.tsx +80 -0
  84. package/src/blocks/Steps/hooks.ts +71 -0
  85. package/src/blocks/Steps/index.tsx +16 -0
  86. package/src/blocks/Steps/types.ts +71 -0
  87. package/src/blocks/StickySectionStack/index.tsx +136 -0
  88. package/src/blocks/Switch/index.tsx +85 -0
  89. package/src/blocks/SystemNotice/index.tsx +81 -0
  90. package/src/blocks/Table/README.md +251 -0
  91. package/src/blocks/Table/Table.tsx +207 -0
  92. package/src/blocks/Table/TablePagination.tsx +189 -0
  93. package/src/blocks/Table/index.ts +33 -0
  94. package/src/blocks/Table/useTableControls.ts +331 -0
  95. package/src/blocks/Tag/index.tsx +27 -0
  96. package/src/blocks/TextBreak/index.tsx +96 -0
  97. package/src/blocks/TextReveal/index.tsx +104 -0
  98. package/src/blocks/Thumbnail/index.tsx +26 -0
  99. package/src/blocks/Ticker/index.tsx +112 -0
  100. package/src/blocks/Toast/index.tsx +77 -0
  101. package/src/blocks/Tooltip/index.tsx +174 -0
  102. package/src/blocks/Underlay/index.tsx +104 -0
  103. package/src/blocks/Upload/Dropzone.tsx +92 -0
  104. package/src/blocks/Upload/UploadBtn.tsx +38 -0
  105. package/src/blocks/Upload/index.tsx +61 -0
  106. package/src/blocks/Upload/types.ts +37 -0
  107. package/src/blocks/VideoMarquee/index.tsx +511 -0
  108. package/src/blocks/index.ts +119 -0
  109. package/src/blocks/pagination/Pagination.tsx +148 -0
  110. package/src/blocks/pagination/PaginationList.tsx +41 -0
  111. package/src/blocks/pagination/index.ts +2 -0
  112. package/src/charts/BarChart.tsx +63 -0
  113. package/src/charts/PieChart.tsx +39 -0
  114. package/src/charts/index.ts +3 -0
  115. package/src/charts/utils.ts +103 -0
  116. package/src/docs/README.md +373 -0
  117. package/src/docs/reference/README.md +299 -0
  118. package/src/elements/box.ts +163 -0
  119. package/src/elements/button.ts +49 -0
  120. package/src/elements/field.ts +129 -0
  121. package/src/elements/index.ts +8 -0
  122. package/src/elements/text.ts +47 -0
  123. package/src/elements/utils.js +97 -0
  124. package/src/hooks/use-copy-to-clipboard.tsx +33 -0
  125. package/src/hooks/use-enter-submit.tsx +23 -0
  126. package/src/hooks/use-local-storage.ts +42 -0
  127. package/src/hooks/use-sidebar.tsx +109 -0
  128. package/src/hooks/useAnimatedText.ts +32 -0
  129. package/src/hooks/useAutosizeTextArea.ts +45 -0
  130. package/src/hooks/useBreakpoint.tsx +123 -0
  131. package/src/hooks/useClickOutside.tsx +38 -0
  132. package/src/hooks/useHover.tsx +33 -0
  133. package/src/hooks/useHoverList.tsx +17 -0
  134. package/src/hooks/useKeyboardShortcuts.ts +91 -0
  135. package/src/hooks/useKeypress.ts +27 -0
  136. package/src/hooks/useOverlay.ts +32 -0
  137. package/src/hooks/useReducedMotion.ts +25 -0
  138. package/src/hooks/useStandaloneMode.ts +35 -0
  139. package/src/hooks/useTouchDevice.ts +34 -0
  140. package/src/icons/index.tsx +129 -0
  141. package/src/index.ts +12 -0
  142. package/src/providers/DesignSystemProvider.tsx +35 -0
  143. package/src/providers/StyledComponentsRegistry.tsx +30 -0
  144. package/src/providers/index.ts +2 -0
  145. package/src/themes/README.md +30 -0
  146. package/src/themes/default/assets/badge-avatar.tsx +45 -0
  147. package/src/themes/default/assets/logo.tsx +42 -0
  148. package/src/themes/default/global.ts +138 -0
  149. package/src/themes/default/modes/dark/config.js +49 -0
  150. package/src/themes/default/modes/dark/skins.js +631 -0
  151. package/src/themes/default/modes/dark/theme.js +87 -0
  152. package/src/themes/default/modes/light/config.js +48 -0
  153. package/src/themes/default/modes/light/skins.js +1026 -0
  154. package/src/themes/default/modes/light/theme.js +74 -0
  155. package/src/themes/default/tokens/controls.js +53 -0
  156. package/src/themes/default/tokens/shadows.js +63 -0
  157. package/src/themes/default/tokens/shapes.js +37 -0
  158. package/src/themes/default/tokens/space.js +143 -0
  159. package/src/themes/default/tokens/spectre.js +16 -0
  160. package/src/themes/default/utils.js +523 -0
  161. package/src/themes/index.ts +11 -0
  162. package/src/types.ts +394 -0
  163. package/src/utils/overlayTheme.ts +61 -0
  164. package/src/utils/pickColor.ts +15 -0
  165. package/tsconfig.json +24 -0
@@ -0,0 +1,163 @@
1
+ "use client";
2
+ import {
3
+ BackgroundProps,
4
+ BorderProps,
5
+ ColorProps,
6
+ FlexboxProps,
7
+ GridProps,
8
+ LayoutProps,
9
+ PositionProps,
10
+ ShadowProps,
11
+ SpaceProps,
12
+ background,
13
+ border,
14
+ color,
15
+ compose,
16
+ flexbox,
17
+ grid,
18
+ layout,
19
+ position,
20
+ shadow,
21
+ space,
22
+ } from "styled-system";
23
+
24
+ import styled, { css } from "styled-components";
25
+ import {
26
+ gap,
27
+ skin,
28
+ shape,
29
+ aspect,
30
+ cursor,
31
+ hover,
32
+ $size,
33
+ focus,
34
+ $shadow,
35
+ disabled,
36
+ } from "./utils";
37
+
38
+ // Base interface that both Box and Text can use
39
+ export interface BaseElementProps
40
+ extends ColorProps,
41
+ SpaceProps,
42
+ LayoutProps,
43
+ PositionProps,
44
+ BackgroundProps,
45
+ BorderProps,
46
+ FlexboxProps,
47
+ GridProps,
48
+ ShadowProps {
49
+ children?: React.ReactNode;
50
+ gap?: any;
51
+ skin?: string;
52
+ shape?: string;
53
+ aspect?: number | number[] | string[] | {};
54
+ cursor?: string;
55
+ hover?: string | object;
56
+ focus?: string | object;
57
+ ref?: any;
58
+ as?: any;
59
+ $size?: any;
60
+ $shadow?: string;
61
+ disabled?: boolean | undefined;
62
+ interactive?: {
63
+ hover?: Record<string, any>;
64
+ focus?: Record<string, any>;
65
+ active?: Record<string, any>;
66
+ disabled?: Record<string, any>;
67
+ visited?: Record<string, any>;
68
+ // Add any other interactive states you need
69
+ };
70
+ [key: string]: any;
71
+ }
72
+
73
+ // Box interface forbids typography props
74
+ export interface BoxProps extends BaseElementProps {}
75
+
76
+ const newArr: any = [];
77
+ const mergeResult = [newArr].concat(
78
+ color.propNames,
79
+ space.propNames,
80
+ flexbox.propNames,
81
+ layout.propNames,
82
+ position.propNames,
83
+ background.propNames,
84
+ border.propNames,
85
+ grid.propNames,
86
+ shadow.propNames,
87
+ );
88
+
89
+ const processInteractiveStyles = (state: string, styles: any) => {
90
+ return (props: any) => {
91
+ const systemStyles = compose(
92
+ color,
93
+ space,
94
+ layout,
95
+ position,
96
+ background,
97
+ border,
98
+ flexbox,
99
+ grid,
100
+ shadow,
101
+ skin,
102
+ shape,
103
+ aspect,
104
+ cursor,
105
+ $size,
106
+ $shadow,
107
+ )({ ...props, ...styles });
108
+
109
+ return css`
110
+ &${`:${state}`} {
111
+ ${systemStyles}
112
+ }
113
+ `;
114
+ };
115
+ };
116
+
117
+ const Box = styled("div").withConfig({
118
+ shouldForwardProp: (prop) =>
119
+ ![
120
+ ...mergeResult,
121
+ "gap",
122
+ "skin",
123
+ "shape",
124
+ "aspect",
125
+ "cursor",
126
+ "interactive",
127
+ ].includes(prop),
128
+ })<BoxProps>`
129
+ ${(props) => {
130
+ return compose(
131
+ color,
132
+ space,
133
+ layout,
134
+ position,
135
+ background,
136
+ border,
137
+ flexbox,
138
+ grid,
139
+ shadow,
140
+ gap,
141
+ skin,
142
+ shape,
143
+ aspect,
144
+ cursor,
145
+ $size,
146
+ $shadow,
147
+ )(props);
148
+ }}
149
+ &:hover {
150
+ ${(p) => p.hover && hover}
151
+ }
152
+ &:focus,
153
+ &:focus-within {
154
+ ${(p) => p.focus && focus}
155
+ }
156
+ ${(p) => p.disabled && disabled}
157
+ ${(p) =>
158
+ p.interactive &&
159
+ Object.entries(p.interactive).map(([state, styles]) =>
160
+ processInteractiveStyles(state, styles),
161
+ )}
162
+ `;
163
+ export default Box;
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import { variant, compose } from "styled-system";
3
+ import styled from "styled-components";
4
+ import Text, { TextProps } from "./text";
5
+ import { disabled } from "./utils";
6
+
7
+ export interface ButtonProps extends TextProps {
8
+ children?: React.ReactNode;
9
+ variant?: string;
10
+ $size?: string;
11
+ disabled?: boolean;
12
+ }
13
+
14
+ const buttonStyle = variant({
15
+ key: "skins.button",
16
+ prop: "variant",
17
+ });
18
+
19
+ const buttonSize = variant({
20
+ key: "skins.button.sizes",
21
+ prop: "$size",
22
+ });
23
+
24
+ const Button = styled(Text).attrs<ButtonProps>((props) => ({
25
+ role: "button",
26
+ border: "none",
27
+ $size: "medium",
28
+ shape: "rounded",
29
+ variant: "default",
30
+ display: "inline-flex",
31
+ alignItems: "center",
32
+ justifyContent: "center",
33
+ cursor: "pointer",
34
+ tabIndex: 0,
35
+ ...props,
36
+ }))<ButtonProps>`
37
+ transition: 0.2s ease;
38
+
39
+ /* Prevent text jiggling during scale animations */
40
+ will-change: transform;
41
+ backface-visibility: hidden;
42
+ -webkit-font-smoothing: subpixel-antialiased;
43
+ transform-style: preserve-3d;
44
+
45
+ ${compose(buttonStyle, buttonSize)}
46
+ ${(p) => p.disabled && disabled}
47
+ `;
48
+
49
+ export default Button;
@@ -0,0 +1,129 @@
1
+ "use client";
2
+ import { variant, compose } from "styled-system";
3
+ import styled, { css } from "styled-components";
4
+ import Text, { TextProps } from "./text";
5
+ import { disabled } from "./utils";
6
+
7
+ export interface FieldProps extends TextProps {
8
+ children?: React.ReactNode;
9
+ variant?: string;
10
+ $size?: string;
11
+ type?: string;
12
+ placeholder?: string;
13
+ autoComplete?: string;
14
+ }
15
+
16
+ const fieldStyle = variant({
17
+ key: "skins.field",
18
+ prop: "variant",
19
+ });
20
+
21
+ const fieldSize = variant({
22
+ key: "skins.field.sizes",
23
+ prop: "$size",
24
+ });
25
+
26
+ // Build array of props that shouldn't be forwarded to DOM
27
+ const newArr: any = [];
28
+ const fieldPropsToOmit = [newArr].concat("variant", "shape", "$size");
29
+
30
+ const selectStyling = css`
31
+ appearance: none;
32
+ /* SVG background image */
33
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg fill='%23212121'%3E%3Cpath d='M12,15a1,1,0,0,1-.707-.293l-4-4A1,1,0,1,1,8.707,9.293L12,12.586l3.293-3.293a1,1,0,0,1,1.414,1.414l-4,4A1,1,0,0,1,12,15Z' fill='gray'%3E%3C/path%3E%3C/g%3E%3C/svg%3E");
34
+ background-size: 1.5em;
35
+ background-position: calc(100% - 0.5em) center;
36
+ background-repeat: no-repeat;
37
+ padding-right: 2em;
38
+ `;
39
+
40
+ const rangeStyling = css`
41
+ --color: ${(p: any) => p.theme.colors.primary};
42
+ --track: ${(p: any) => p.theme.colors.transparent.light[2]};
43
+ --shadow: ${(p: any) => p.theme.colors.dark};
44
+
45
+ /*********** Baseline, reset styles ***********/
46
+
47
+ -webkit-appearance: none;
48
+ appearance: none;
49
+ background: transparent;
50
+ border: none;
51
+ cursor: pointer;
52
+ width: 100%;
53
+ padding: 0;
54
+
55
+ /* Removes default focus */
56
+ &:hover,
57
+ &:focus {
58
+ outline: none;
59
+ }
60
+
61
+ /******** Chrome, Safari, Opera and Edge Chromium styles ********/
62
+ /* slider track */
63
+ &::-webkit-slider-runnable-track {
64
+ background-color: var(--track);
65
+ border-radius: 0.5rem;
66
+ height: 0.5rem;
67
+ }
68
+
69
+ /* slider thumb */
70
+ &::-webkit-slider-thumb {
71
+ -webkit-appearance: none; /* Override default look */
72
+ appearance: none;
73
+ margin-top: -4px; /* Centers thumb on the track */
74
+ background-color: var(--color);
75
+ border-radius: 0.5rem;
76
+ height: 1rem;
77
+ width: 1rem;
78
+ }
79
+
80
+ &:focus::-webkit-slider-thumb {
81
+ outline: 3px solid var(--color);
82
+ outline-offset: 0.125rem;
83
+ }
84
+
85
+ /*********** Firefox styles ***********/
86
+ /* slider track */
87
+ &::-moz-range-track {
88
+ background-color: var(--track);
89
+ border-radius: 0.5rem;
90
+ height: 0.5rem;
91
+ }
92
+
93
+ /* slider thumb */
94
+ &::-moz-range-thumb {
95
+ background-color: var(--color);
96
+ border: none; /*Removes extra border that FF applies*/
97
+ border-radius: 0.5rem;
98
+ height: 1rem;
99
+ width: 1rem;
100
+ }
101
+
102
+ &:focus::-moz-range-thumb {
103
+ outline: 3px solid var(--shadow);
104
+ //outline-offset: 0.125rem;
105
+ }
106
+ `;
107
+
108
+ const Field = styled(Text)
109
+ .withConfig({
110
+ shouldForwardProp: (prop) => !fieldPropsToOmit.includes(prop),
111
+ })
112
+ .attrs<FieldProps>((props) => ({
113
+ as: "input",
114
+ type: "text",
115
+ shape: "rounded",
116
+ variant: "default",
117
+ display: "inline-flex",
118
+ $size: "medium",
119
+ placeholder: "",
120
+ ...props,
121
+ }))<FieldProps>`
122
+ ${compose(fieldStyle, fieldSize)}
123
+ ${(p) => p.disabled && disabled}
124
+ ${(p) => p.as === "select" && selectStyling}
125
+ ${(p) => p.type === "range" && rangeStyling}
126
+ transition: 0.2s ease;
127
+ `;
128
+
129
+ export default Field;
@@ -0,0 +1,8 @@
1
+ export { default as Box } from "./box";
2
+ export type { BoxProps, BaseElementProps } from "./box";
3
+ export { default as Button } from "./button";
4
+ export type { ButtonProps } from "./button";
5
+ export { default as Field } from "./field";
6
+ export type { FieldProps } from "./field";
7
+ export { default as Text } from "./text";
8
+ export type { TextProps } from "./text";
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { typography, TypographyProps, compose } from "styled-system";
3
+ import styled from "styled-components";
4
+ import Box, { BaseElementProps } from "./box";
5
+ import {
6
+ textTransform,
7
+ textDecoration,
8
+ textOverflow,
9
+ truncate,
10
+ lineClamp,
11
+ disabled,
12
+ } from "./utils";
13
+
14
+ export interface TextProps extends BaseElementProps, TypographyProps {
15
+ children?: React.ReactNode;
16
+ truncate?: boolean;
17
+ textTransform?: string;
18
+ textDecoration?: string;
19
+ lineClamp?: number;
20
+ }
21
+
22
+ const newArr: any = [];
23
+ const mergeResult = [newArr].concat(typography.propNames);
24
+
25
+ const Text = styled(Box)
26
+ .withConfig({
27
+ shouldForwardProp: (prop) =>
28
+ ![
29
+ ...mergeResult,
30
+ "textTransform",
31
+ "textDecoration",
32
+ "textOverflow",
33
+ "truncate",
34
+ "lineClamp",
35
+ ].includes(prop),
36
+ })
37
+ .attrs<TextProps>((props) => ({
38
+ as: "span",
39
+ ...props,
40
+ }))<TextProps>`
41
+ ${(p) => (p.truncate ? truncate : null)}
42
+ ${(p) => (p.lineClamp ? lineClamp : null)}
43
+ ${() => compose(typography, textTransform, textDecoration, textOverflow)}
44
+ ${(p) => p.disabled && disabled}
45
+ `;
46
+
47
+ export default Text;
@@ -0,0 +1,97 @@
1
+ import { style, variant } from "styled-system"
2
+ import { css } from "styled-components"
3
+
4
+ export const disabled = css`
5
+ opacity: 0.5;
6
+ pointer-events: none;
7
+ `
8
+
9
+ // used by Box
10
+
11
+ export const gap = style({
12
+ prop: "gap",
13
+ cssProperty: "gap",
14
+ key: "space",
15
+ })
16
+
17
+ export const aspect = style({
18
+ prop: "aspect",
19
+ cssProperty: "aspectRatio",
20
+ })
21
+
22
+ export const $size = variant({
23
+ key: "controlSizes",
24
+ prop: "$size",
25
+ })
26
+
27
+ export const skin = variant({
28
+ key: "skins",
29
+ prop: "skin",
30
+ })
31
+
32
+ export const hover = variant({
33
+ key: "skins",
34
+ prop: "hover",
35
+ })
36
+
37
+ export const $shadow = variant({
38
+ key: "shadows",
39
+ prop: "$shadow",
40
+ })
41
+
42
+ export const focus = variant({
43
+ key: "skins",
44
+ prop: "focus",
45
+ })
46
+
47
+ export const shape = variant({
48
+ key: "shapes",
49
+ prop: "shape",
50
+ cssProperty: "border-radius",
51
+ })
52
+
53
+ export const cursor = style({
54
+ prop: "cursor",
55
+ cssProperty: "cursor",
56
+ })
57
+
58
+ // used by Text
59
+ export const textTransform = style({
60
+ prop: "textTransform",
61
+ cssProperty: "text-transform",
62
+ })
63
+
64
+ export const textDecoration = style({
65
+ prop: "textDecoration",
66
+ cssProperty: "text-decoration",
67
+ })
68
+
69
+ export const textOverflow = style({
70
+ prop: "textOverflow",
71
+ cssProperty: "text-overflow",
72
+ })
73
+
74
+ export const outline = css`
75
+ box-shadow: 0 0 0px 1px ${(p) =>
76
+ p.theme.colors.palette.neutrals[8]}, 0 0 0px 4px ${(p) =>
77
+ p.theme.colors.palette.blues[5]}
78
+ }`
79
+
80
+ export const lineClamp = css`
81
+ max-width: 100%;
82
+ display: -webkit-box;
83
+ text-wrap: balance;
84
+ -webkit-line-clamp: ${(p) => p.lineClamp || 1};
85
+ overflow: hidden;
86
+ word-break: break-word;
87
+ text-overflow: ellipsis;
88
+ -webkit-box-orient: vertical;
89
+ `
90
+
91
+ export const truncate = css`
92
+ width: 100%;
93
+ white-space: nowrap;
94
+ overflow: hidden;
95
+ text-overflow: ellipsis;
96
+ display: inline-block;
97
+ `
@@ -0,0 +1,33 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+
5
+ export interface useCopyToClipboardProps {
6
+ timeout?: number;
7
+ }
8
+
9
+ export function useCopyToClipboard({
10
+ timeout = 2000,
11
+ }: useCopyToClipboardProps) {
12
+ const [isCopied, setIsCopied] = React.useState<boolean>(false);
13
+
14
+ const copyToClipboard = (value: string) => {
15
+ if (typeof window === "undefined" || !navigator.clipboard?.writeText) {
16
+ return;
17
+ }
18
+
19
+ if (!value) {
20
+ return;
21
+ }
22
+
23
+ navigator.clipboard.writeText(value).then(() => {
24
+ setIsCopied(true);
25
+
26
+ setTimeout(() => {
27
+ setIsCopied(false);
28
+ }, timeout);
29
+ });
30
+ };
31
+
32
+ return { isCopied, copyToClipboard };
33
+ }
@@ -0,0 +1,23 @@
1
+ import { useRef, type RefObject } from "react";
2
+
3
+ export function useEnterSubmit(): {
4
+ formRef: RefObject<HTMLFormElement | null>;
5
+ onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
6
+ } {
7
+ const formRef = useRef<HTMLFormElement | null>(null);
8
+
9
+ const handleKeyDown = (
10
+ event: React.KeyboardEvent<HTMLTextAreaElement>,
11
+ ): void => {
12
+ if (
13
+ event.key === "Enter" &&
14
+ !event.shiftKey &&
15
+ !event.nativeEvent.isComposing
16
+ ) {
17
+ formRef.current?.requestSubmit();
18
+ event.preventDefault();
19
+ }
20
+ };
21
+
22
+ return { formRef, onKeyDown: handleKeyDown };
23
+ }
@@ -0,0 +1,42 @@
1
+ import { useCallback, useState } from "react";
2
+
3
+ export const useLocalStorage = <T,>(
4
+ key: string,
5
+ initialValue: T,
6
+ ): [T, (value: T) => void] => {
7
+ const [storedValue, setStoredValue] = useState<T>(() => {
8
+ if (typeof window === "undefined") {
9
+ return initialValue;
10
+ }
11
+
12
+ try {
13
+ const item = window.localStorage.getItem(key);
14
+ if (!item) return initialValue;
15
+
16
+ try {
17
+ return JSON.parse(item) as T;
18
+ } catch {
19
+ return item as T;
20
+ }
21
+ } catch (error) {
22
+ console.error(error);
23
+ return initialValue;
24
+ }
25
+ });
26
+
27
+ const setValue = useCallback(
28
+ (value: T) => {
29
+ try {
30
+ setStoredValue(value);
31
+ if (typeof window !== "undefined") {
32
+ window.localStorage.setItem(key, JSON.stringify(value));
33
+ }
34
+ } catch (error) {
35
+ console.error(error);
36
+ }
37
+ },
38
+ [key],
39
+ );
40
+
41
+ return [storedValue, setValue];
42
+ };
@@ -0,0 +1,109 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+
5
+ const LOCAL_STORAGE_PREFIX = "panel_";
6
+
7
+ interface SidebarState {
8
+ isOpen: boolean;
9
+ }
10
+
11
+ interface SidebarContextValue {
12
+ getSidebarState: (id: string) => SidebarState;
13
+ toggleSidebar: (id: string) => void;
14
+ isLoading: boolean;
15
+ }
16
+
17
+ const SidebarContext = React.createContext<SidebarContextValue | undefined>(
18
+ undefined,
19
+ );
20
+
21
+ export function useSidebar(id: string) {
22
+ const context = React.useContext(SidebarContext);
23
+
24
+ if (!context) {
25
+ console.warn("useSidebar must be used within a SidebarProvider");
26
+ return {
27
+ isSidebarOpen: false,
28
+ toggleSidebar: () => {},
29
+ isLoading: true,
30
+ };
31
+ }
32
+
33
+ return {
34
+ isSidebarOpen: context.getSidebarState(id).isOpen,
35
+ toggleSidebar: () => context.toggleSidebar(id),
36
+ isLoading: context.isLoading,
37
+ };
38
+ }
39
+
40
+ export function SidebarProvider({ children }: { children: React.ReactNode }) {
41
+ const [sidebarStates, setSidebarStates] = React.useState<
42
+ Record<string, SidebarState>
43
+ >({});
44
+ const [isLoading, setLoading] = React.useState(true);
45
+
46
+ React.useEffect(() => {
47
+ let isMounted = true;
48
+
49
+ try {
50
+ const storedStates: Record<string, SidebarState> = {};
51
+ for (let index = 0; index < localStorage.length; index += 1) {
52
+ const key = localStorage.key(index);
53
+ if (key?.startsWith(LOCAL_STORAGE_PREFIX)) {
54
+ const id = key.slice(LOCAL_STORAGE_PREFIX.length);
55
+ storedStates[id] = JSON.parse(localStorage.getItem(key) || "{}");
56
+ }
57
+ }
58
+
59
+ if (isMounted) {
60
+ setSidebarStates(storedStates);
61
+ }
62
+ } catch (error) {
63
+ console.error("Failed to load sidebar states:", error);
64
+ } finally {
65
+ if (isMounted) {
66
+ setLoading(false);
67
+ }
68
+ }
69
+
70
+ return () => {
71
+ isMounted = false;
72
+ };
73
+ }, []);
74
+
75
+ const getSidebarState = React.useCallback(
76
+ (id: string): SidebarState => sidebarStates[id] || { isOpen: false },
77
+ [sidebarStates],
78
+ );
79
+
80
+ const toggleSidebar = React.useCallback(
81
+ (id: string) => {
82
+ setSidebarStates((prevStates) => {
83
+ const current = prevStates[id] || { isOpen: false };
84
+ const nextState = {
85
+ ...prevStates,
86
+ [id]: { isOpen: !current.isOpen },
87
+ };
88
+
89
+ try {
90
+ localStorage.setItem(
91
+ `${LOCAL_STORAGE_PREFIX}${id}`,
92
+ JSON.stringify(nextState[id]),
93
+ );
94
+ } catch (error) {
95
+ console.error("Failed to save sidebar state:", error);
96
+ }
97
+
98
+ return nextState;
99
+ });
100
+ },
101
+ [],
102
+ );
103
+
104
+ return (
105
+ <SidebarContext.Provider value={{ getSidebarState, toggleSidebar, isLoading }}>
106
+ {children}
107
+ </SidebarContext.Provider>
108
+ );
109
+ }