cherry-styled-components 0.1.18 → 0.2.0

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.
@@ -0,0 +1,255 @@
1
+ "use client";
2
+ "use client";
3
+ import { mq } from "./utils/theme.js";
4
+ import { resetButton } from "./utils/mixins.js";
5
+ import { Icon } from "./icon.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
8
+ import styled, { css } from "styled-components";
9
+ import { rgba } from "polished";
10
+ //#region src/lib/dropzone.tsx
11
+ /** Matches a file against an `accept` string (".pdf,image/*,text/plain"),
12
+ mirroring the native file-picker filter for dropped files. */ var matchesAccept = (file, accept) => {
13
+ if (!accept) return true;
14
+ return accept.split(",").some((raw) => {
15
+ const entry = raw.trim().toLowerCase();
16
+ if (!entry) return false;
17
+ if (entry.startsWith(".")) return file.name.toLowerCase().endsWith(entry);
18
+ if (entry.endsWith("/*")) return file.type.toLowerCase().startsWith(entry.slice(0, -1));
19
+ return file.type.toLowerCase() === entry;
20
+ });
21
+ };
22
+ function LocalDropzone({ $prompt = "Drag & drop files here", $browse, $hint, $icon = "FileUp", $inline, $maxFiles, $maxBytes, onFilesChange, onFilesRejected, accept, multiple, disabled, ...rest }, ref) {
23
+ const [items, setItems] = useState([]);
24
+ const [dragOver, setDragOver] = useState(false);
25
+ const inputRef = useRef(null);
26
+ useImperativeHandle(ref, () => inputRef.current);
27
+ const itemsRef = useRef([]);
28
+ itemsRef.current = items;
29
+ useEffect(() => {
30
+ return () => {
31
+ itemsRef.current.forEach((item) => item.previewUrl && URL.revokeObjectURL(item.previewUrl));
32
+ };
33
+ }, []);
34
+ const limit = multiple ? $maxFiles ?? Infinity : 1;
35
+ const atLimit = items.length >= limit;
36
+ const addFiles = (fileList) => {
37
+ if (!fileList || disabled) return;
38
+ const files = Array.from(fileList);
39
+ const rejections = [];
40
+ const accepted = [];
41
+ const replacing = !multiple && files.length > 0;
42
+ const remaining = replacing ? 1 : limit - items.length;
43
+ for (const file of files) {
44
+ if (accepted.length >= remaining) {
45
+ rejections.push({
46
+ file,
47
+ reason: "count"
48
+ });
49
+ continue;
50
+ }
51
+ if (!matchesAccept(file, accept)) {
52
+ rejections.push({
53
+ file,
54
+ reason: "type"
55
+ });
56
+ continue;
57
+ }
58
+ if ($maxBytes && file.size > $maxBytes) {
59
+ rejections.push({
60
+ file,
61
+ reason: "size"
62
+ });
63
+ continue;
64
+ }
65
+ accepted.push({
66
+ key: `${file.name}-${file.size}-${Date.now()}-${accepted.length}`,
67
+ file,
68
+ previewUrl: file.type.startsWith("image/") ? URL.createObjectURL(file) : null
69
+ });
70
+ }
71
+ if (rejections.length > 0) onFilesRejected?.(rejections);
72
+ if (accepted.length === 0) return;
73
+ setItems((current) => {
74
+ const kept = replacing ? [] : current;
75
+ if (replacing) current.forEach((item) => item.previewUrl && URL.revokeObjectURL(item.previewUrl));
76
+ const next = [...kept, ...accepted];
77
+ onFilesChange?.(next.map((item) => item.file));
78
+ return next;
79
+ });
80
+ };
81
+ const removeItem = (key) => {
82
+ setItems((current) => {
83
+ const item = current.find((it) => it.key === key);
84
+ if (item?.previewUrl) URL.revokeObjectURL(item.previewUrl);
85
+ const next = current.filter((it) => it.key !== key);
86
+ onFilesChange?.(next.map((it) => it.file));
87
+ return next;
88
+ });
89
+ };
90
+ const openPicker = () => {
91
+ if (disabled || atLimit) return;
92
+ inputRef.current?.click();
93
+ };
94
+ return /*#__PURE__*/ jsxs(StyledDropzoneWrapper, { children: [
95
+ /*#__PURE__*/ jsxs(StyledDropzone, {
96
+ type: "button",
97
+ "aria-label": $prompt,
98
+ $dragOver: dragOver,
99
+ $inline,
100
+ disabled: disabled || atLimit,
101
+ onClick: openPicker,
102
+ onDragOver: (e) => {
103
+ e.preventDefault();
104
+ if (!disabled && !atLimit) setDragOver(true);
105
+ },
106
+ onDragLeave: () => setDragOver(false),
107
+ onDrop: (e) => {
108
+ e.preventDefault();
109
+ setDragOver(false);
110
+ addFiles(e.dataTransfer.files);
111
+ },
112
+ children: [
113
+ /*#__PURE__*/ jsx(StyledDropIcon, {
114
+ $inline,
115
+ children: /*#__PURE__*/ jsx(Icon, { name: $icon })
116
+ }),
117
+ /*#__PURE__*/ jsxs(StyledDropPrompt, {
118
+ $inline,
119
+ children: [$prompt, $browse ? /*#__PURE__*/ jsx("span", { children: $browse }) : null]
120
+ }),
121
+ $hint ? /*#__PURE__*/ jsx(StyledDropHint, {
122
+ $inline,
123
+ children: $hint
124
+ }) : null
125
+ ]
126
+ }),
127
+ /*#__PURE__*/ jsx("input", {
128
+ ref: inputRef,
129
+ type: "file",
130
+ accept,
131
+ multiple,
132
+ disabled,
133
+ hidden: true,
134
+ onChange: (e) => {
135
+ addFiles(e.target.files);
136
+ e.target.value = "";
137
+ },
138
+ ...rest
139
+ }),
140
+ items.length > 0 && /*#__PURE__*/ jsx(StyledThumbs, { children: items.map((item) => /*#__PURE__*/ jsxs(StyledThumb, {
141
+ title: item.file.name,
142
+ children: [item.previewUrl ? /*#__PURE__*/ jsx("img", {
143
+ src: item.previewUrl,
144
+ alt: item.file.name
145
+ }) : /*#__PURE__*/ jsxs(StyledThumbFile, { children: [/*#__PURE__*/ jsx(Icon, { name: "File" }), /*#__PURE__*/ jsx("span", { children: item.file.name })] }), /*#__PURE__*/ jsx(StyledThumbRemove, {
146
+ type: "button",
147
+ "aria-label": `Remove ${item.file.name}`,
148
+ onClick: () => removeItem(item.key),
149
+ disabled,
150
+ children: /*#__PURE__*/ jsx(Icon, { name: "X" })
151
+ })]
152
+ }, item.key)) })
153
+ ] });
154
+ }
155
+ var Dropzone = /*#__PURE__*/ forwardRef(LocalDropzone);
156
+ var StyledDropzoneWrapper = styled.div.withConfig({
157
+ displayName: "dropzone__StyledDropzoneWrapper",
158
+ componentId: "sc-cf1c3c01-0"
159
+ })([`display:flex;flex-direction:column;gap:12px;width:100%;`]);
160
+ var StyledDropzone = styled.button.withConfig({
161
+ displayName: "dropzone__StyledDropzone",
162
+ componentId: "sc-cf1c3c01-1"
163
+ })([
164
+ ``,
165
+ `;display:flex;flex-direction:`,
166
+ `;align-items:center;justify-content:center;gap:`,
167
+ `;width:100%;padding:`,
168
+ `;border-radius:`,
169
+ `;border:2px dashed `,
170
+ `;background:`,
171
+ `;color:`,
172
+ `;text-align:`,
173
+ `;transition:all 0.3s ease;`,
174
+ ` @media (hover:hover){&:hover:not(:disabled){border-color:`,
175
+ `;background:`,
176
+ `;}}&:focus{border-color:`,
177
+ `;box-shadow:0 0 0 4px `,
178
+ `;}&:disabled{cursor:not-allowed;opacity:0.6;}`
179
+ ], resetButton, ({ $inline }) => $inline ? "row" : "column", ({ $inline }) => $inline ? "10px" : "8px", ({ $inline }) => $inline ? "10px 14px" : "24px 20px", ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.colors.grayLight, ({ theme, $inline }) => $inline ? "transparent" : theme.colors.light, ({ theme }) => theme.colors.grayDark, ({ $inline }) => $inline ? "left" : "center", ({ theme, $dragOver }) => $dragOver && css([
180
+ `border-color:`,
181
+ `;background:`,
182
+ `;`
183
+ ], theme.colors.primary, rgba(theme.colors.primary, theme.isDark ? .12 : .05)), ({ theme }) => theme.colors.primary, ({ theme }) => rgba(theme.colors.primary, theme.isDark ? .1 : .04), ({ theme }) => theme.colors.primary, ({ theme }) => theme.colors.primaryLight);
184
+ var StyledDropIcon = styled.span.withConfig({
185
+ displayName: "dropzone__StyledDropIcon",
186
+ componentId: "sc-cf1c3c01-2"
187
+ })([
188
+ `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:`,
189
+ `;height:`,
190
+ `;border-radius:`,
191
+ `;background:`,
192
+ `;border:solid 1px `,
193
+ `;color:`,
194
+ `;transition:all 0.3s ease;& svg{width:`,
195
+ `;height:`,
196
+ `;}`
197
+ ], ({ $inline }) => $inline ? "32px" : "44px", ({ $inline }) => $inline ? "32px" : "44px", ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.primary, ({ $inline }) => $inline ? "18px" : "22px", ({ $inline }) => $inline ? "18px" : "22px");
198
+ var StyledDropPrompt = styled.span.withConfig({
199
+ displayName: "dropzone__StyledDropPrompt",
200
+ componentId: "sc-cf1c3c01-3"
201
+ })([
202
+ `display:flex;flex-direction:`,
203
+ `;flex-wrap:wrap;align-items:baseline;gap:`,
204
+ `;font-family:`,
205
+ `;font-size:`,
206
+ `;line-height:`,
207
+ `;font-weight:600;color:`,
208
+ `;& span{font-weight:500;color:`,
209
+ `;}`
210
+ ], ({ $inline }) => $inline ? "row" : "column", ({ $inline }) => $inline ? "0 6px" : "2px", ({ theme }) => theme.fonts.text, ({ theme }) => theme.fontSizes.text.xs, ({ theme }) => theme.lineHeights.text.xs, ({ theme }) => theme.colors.dark, ({ theme }) => theme.colors.grayDark);
211
+ var StyledDropHint = styled.span.withConfig({
212
+ displayName: "dropzone__StyledDropHint",
213
+ componentId: "sc-cf1c3c01-4"
214
+ })([
215
+ `font-family:`,
216
+ `;font-size:`,
217
+ `;line-height:`,
218
+ `;color:`,
219
+ `;`,
220
+ ``
221
+ ], ({ theme }) => theme.fonts.text, ({ theme }) => theme.fontSizes.small.xs, ({ theme }) => theme.lineHeights.small.xs, ({ theme }) => theme.colors.gray, ({ $inline }) => $inline && css([`margin-left:auto;`]));
222
+ var StyledThumbs = styled.div.withConfig({
223
+ displayName: "dropzone__StyledThumbs",
224
+ componentId: "sc-cf1c3c01-5"
225
+ })([`display:grid;grid-template-columns:repeat(auto-fill,72px);gap:10px;`, `{grid-template-columns:repeat(auto-fill,84px);}`], mq("sm"));
226
+ var StyledThumb = styled.div.withConfig({
227
+ displayName: "dropzone__StyledThumb",
228
+ componentId: "sc-cf1c3c01-6"
229
+ })([
230
+ `position:relative;width:72px;height:72px;border-radius:`,
231
+ `;overflow:hidden;border:solid 1px `,
232
+ `;background:`,
233
+ `;& img{width:100%;height:100%;object-fit:cover;display:block;}`,
234
+ `{width:84px;height:84px;}`
235
+ ], ({ theme }) => theme.spacing.radius.lg, ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.light, mq("sm"));
236
+ var StyledThumbFile = styled.span.withConfig({
237
+ displayName: "dropzone__StyledThumbFile",
238
+ componentId: "sc-cf1c3c01-7"
239
+ })([
240
+ `display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;width:100%;height:100%;padding:6px;color:`,
241
+ `;& svg{width:20px;height:20px;color:`,
242
+ `;}& span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:`,
243
+ `;font-size:10px;line-height:1.2;}`
244
+ ], ({ theme }) => theme.colors.grayDark, ({ theme }) => theme.colors.primary, ({ theme }) => theme.fonts.text);
245
+ var StyledThumbRemove = styled.button.withConfig({
246
+ displayName: "dropzone__StyledThumbRemove",
247
+ componentId: "sc-cf1c3c01-8"
248
+ })([
249
+ ``,
250
+ `;position:absolute;top:4px;right:4px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;color:#ffffff;background:`,
251
+ `;transition:background 0.3s ease;& svg{width:14px;height:14px;}@media (hover:hover){&:hover:not(:disabled){background:`,
252
+ `;}}&:disabled{cursor:not-allowed;opacity:0.6;}`
253
+ ], resetButton, ({ theme }) => rgba(theme.colors.dark, .6), ({ theme }) => theme.colors.error);
254
+ //#endregion
255
+ export { Dropzone, matchesAccept };
@@ -0,0 +1,11 @@
1
+ import { default as React } from 'react';
2
+ import { Theme } from './utils';
3
+ export interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
+ children?: React.ReactNode;
5
+ "aria-label": string;
6
+ $size?: "default" | "big" | "small";
7
+ $error?: boolean;
8
+ }
9
+ export declare const iconButtonStyles: (theme: Theme, $size?: "default" | "big" | "small", $error?: boolean, disabled?: boolean) => import('styled-components').RuleSet<object>;
10
+ declare const IconButton: React.ForwardRefExoticComponent<IconButtonProps & React.RefAttributes<HTMLButtonElement>>;
11
+ export { IconButton };
@@ -0,0 +1,72 @@
1
+ "use client";
2
+ "use client";
3
+ import { resetButton } from "./utils/mixins.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { forwardRef } from "react";
6
+ import styled, { css } from "styled-components";
7
+ import { darken, lighten } from "polished";
8
+ //#region src/lib/icon-button.tsx
9
+ var iconButtonSizes = {
10
+ small: {
11
+ box: 24,
12
+ icon: 12
13
+ },
14
+ default: {
15
+ box: 28,
16
+ icon: 14
17
+ },
18
+ big: {
19
+ box: 32,
20
+ icon: 16
21
+ }
22
+ };
23
+ var iconButtonStyles = (theme, $size, $error, disabled) => {
24
+ const { box, icon } = iconButtonSizes[$size ?? "default"];
25
+ return css([
26
+ ``,
27
+ `;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:`,
28
+ `px;height:`,
29
+ `px;border-radius:50%;background:`,
30
+ `;border:solid 2px `,
31
+ `;color:`,
32
+ `;box-shadow:0 0 0 0px `,
33
+ `;transition:all 0.3s ease;& svg{width:`,
34
+ `px;height:`,
35
+ `px;}`,
36
+ ` `,
37
+ ``
38
+ ], resetButton, box, box, theme.colors.light, theme.colors.grayLight, $error ? theme.colors.error : theme.colors.grayDark, $error ? lighten(.1, theme.colors.error) : theme.colors.primaryLight, icon, icon, !disabled && ($error ? css([
39
+ `border-color:`,
40
+ `;&:hover{border-color:`,
41
+ `;color:`,
42
+ `;}&:focus{box-shadow:0 0 0 4px `,
43
+ `;}&:active{box-shadow:0 0 0 2px `,
44
+ `;}`
45
+ ], theme.colors.error, darken(.1, theme.colors.error), darken(.1, theme.colors.error), lighten(.1, theme.colors.error), lighten(.1, theme.colors.error)) : css([
46
+ `&:hover{border-color:`,
47
+ `;color:`,
48
+ `;}&:focus{box-shadow:0 0 0 4px `,
49
+ `;border-color:`,
50
+ `;}&:active{box-shadow:0 0 0 2px `,
51
+ `;}`
52
+ ], theme.colors.primary, theme.colors.primary, theme.colors.primaryLight, theme.colors.primary, theme.colors.primaryLight)), disabled && css([
53
+ `cursor:not-allowed;background:`,
54
+ `;border-color:`,
55
+ `;color:`,
56
+ `;`
57
+ ], theme.colors.grayLight, theme.colors.grayLight, theme.colors.gray));
58
+ };
59
+ var StyledIconButton = styled.button.withConfig({
60
+ displayName: "icon-button__StyledIconButton",
61
+ componentId: "sc-def35ae6-0"
62
+ })([``, ``], ({ theme, $size, $error, disabled }) => iconButtonStyles(theme, $size, $error, disabled));
63
+ function LocalIconButton({ ...props }, ref) {
64
+ return /*#__PURE__*/ jsx(StyledIconButton, {
65
+ type: "button",
66
+ ...props,
67
+ ref
68
+ });
69
+ }
70
+ var IconButton = /*#__PURE__*/ forwardRef(LocalIconButton);
71
+ //#endregion
72
+ export { IconButton, iconButtonStyles };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,24 @@
1
1
  export * from './styled-components';
2
2
  export * from './utils';
3
+ export * from './accordion';
4
+ export * from './avatar-dropzone';
3
5
  export * from './box';
4
6
  export * from './button';
5
7
  export * from './col';
6
8
  export * from './container';
9
+ export * from './dropzone';
7
10
  export * from './flex';
8
11
  export * from './grid';
9
12
  export * from './icon';
13
+ export * from './icon-button';
10
14
  export * from './input';
11
15
  export * from './max-width';
16
+ export * from './modal';
17
+ export * from './password';
12
18
  export * from './range';
13
19
  export * from './select';
14
20
  export * from './space';
15
21
  export * from './textarea';
22
+ export * from './theme-toggle';
23
+ export * from './toast';
16
24
  export * from './toggle';
package/dist/index.js CHANGED
@@ -1,22 +1,33 @@
1
- import { StyledComponentsRegistry } from "./styled-components/registry.js";
2
1
  import { GlobalStyles } from "./utils/global.js";
3
2
  import { IconArrow, IconCalendar, IconCheck } from "./utils/icons.js";
4
3
  import { breakpoints, colors, colorsDark, fontSizes, fonts, lineHeights, mq, shadows, shadowsDark, spacing, theme, themeDark } from "./utils/theme.js";
5
- import { formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, resetButton, resetInput, statusBorderStyles } from "./utils/mixins.js";
4
+ import { errorInteractiveStyles, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, interactiveStyles, resetButton, resetInput, statusBorderStyles } from "./utils/mixins.js";
6
5
  import { createTypographyStyle, styledBlockquote, styledButton, styledButtonBig, styledCode, styledH1, styledH2, styledH3, styledH4, styledH5, styledH6, styledHero1, styledHero2, styledHero3, styledInput, styledInputBig, styledSmall, styledStrong, styledText } from "./utils/typography.js";
6
+ import { useOnClickOutside } from "./utils/use-on-click-outside.js";
7
7
  import { CherryThemeProvider, ThemeContext } from "./styled-components/theme-provider.js";
8
+ import { ClientThemeProvider } from "./styled-components/client-theme-provider.js";
9
+ import { StyledComponentsRegistry } from "./styled-components/registry.js";
10
+ import { createThemeInitScript, resolveTheme, themeInitScript } from "./styled-components/theme-init.js";
11
+ import { Icon } from "./icon.js";
12
+ import { Accordion } from "./accordion.js";
13
+ import { Dropzone, matchesAccept } from "./dropzone.js";
14
+ import { AvatarDropzone } from "./avatar-dropzone.js";
8
15
  import { Container } from "./container.js";
9
16
  import { Box } from "./box.js";
10
17
  import { Button, buttonStyles } from "./button.js";
11
18
  import { Col } from "./col.js";
12
19
  import { Flex } from "./flex.js";
13
20
  import { Grid } from "./grid.js";
14
- import { Icon } from "./icon.js";
21
+ import { IconButton, iconButtonStyles } from "./icon-button.js";
15
22
  import { Input, StyledInputWrapper, StyledLabel } from "./input.js";
16
23
  import { MaxWidth } from "./max-width.js";
24
+ import { Modal } from "./modal.js";
25
+ import { Password } from "./password.js";
17
26
  import { Range } from "./range.js";
18
27
  import { Select, StyledIconWrapper } from "./select.js";
19
28
  import { Space } from "./space.js";
20
29
  import { Textarea } from "./textarea.js";
30
+ import { ThemeToggle } from "./theme-toggle.js";
31
+ import { StyledNotifications, ToastNotifications, ToastNotificationsContext, ToastNotificationsProvider, useToastNotifications } from "./toast.js";
21
32
  import { Toggle } from "./toggle.js";
22
- export { Box, Button, CherryThemeProvider, Col, Container, Flex, GlobalStyles, Grid, Icon, IconArrow, IconCalendar, IconCheck, Input, MaxWidth, Range, Select, Space, StyledComponentsRegistry, StyledIconWrapper, StyledInputWrapper, StyledLabel, Textarea, ThemeContext, Toggle, breakpoints, buttonStyles, colors, colorsDark, createTypographyStyle, fontSizes, fonts, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, lineHeights, mq, resetButton, resetInput, shadows, shadowsDark, spacing, statusBorderStyles, styledBlockquote, styledButton, styledButtonBig, styledCode, styledH1, styledH2, styledH3, styledH4, styledH5, styledH6, styledHero1, styledHero2, styledHero3, styledInput, styledInputBig, styledSmall, styledStrong, styledText, theme, themeDark };
33
+ export { Accordion, AvatarDropzone, Box, Button, CherryThemeProvider, ClientThemeProvider, Col, Container, Dropzone, Flex, GlobalStyles, Grid, Icon, IconArrow, IconButton, IconCalendar, IconCheck, Input, MaxWidth, Modal, Password, Range, Select, Space, StyledComponentsRegistry, StyledIconWrapper, StyledInputWrapper, StyledLabel, StyledNotifications, Textarea, ThemeContext, ThemeToggle, ToastNotifications, ToastNotificationsContext, ToastNotificationsProvider, Toggle, breakpoints, buttonStyles, colors, colorsDark, createThemeInitScript, createTypographyStyle, errorInteractiveStyles, fontSizes, fonts, formElementHeightStyles, fullWidthStyles, generateAlignContentStyles, generateAlignItemsStyles, generateColSpanStyles, generateColsStyles, generateDirectionStyles, generateGapStyles, generateJustifyContentStyles, generatePaddingStyles, iconButtonStyles, interactiveStyles, lineHeights, matchesAccept, mq, resetButton, resetInput, resolveTheme, shadows, shadowsDark, spacing, statusBorderStyles, styledBlockquote, styledButton, styledButtonBig, styledCode, styledH1, styledH2, styledH3, styledH4, styledH5, styledH6, styledHero1, styledHero2, styledHero3, styledInput, styledInputBig, styledSmall, styledStrong, styledText, theme, themeDark, themeInitScript, useOnClickOutside, useToastNotifications };
package/dist/input.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { default as React } from 'react';
2
2
  import { IStyledComponent } from 'styled-components';
3
- interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
3
+ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
4
4
  children?: React.ReactNode;
5
5
  $wrapperClassName?: string;
6
6
  $label?: string;
package/dist/input.js CHANGED
@@ -8,7 +8,7 @@ import styled, { css } from "styled-components";
8
8
  //#region src/lib/input.tsx
9
9
  var StyledInputWrapper = styled.span.withConfig({
10
10
  displayName: "input__StyledInputWrapper",
11
- componentId: "sc-df1aa532-0"
11
+ componentId: "sc-f9d22714-0"
12
12
  })([
13
13
  `display:inline-flex;flex-wrap:`,
14
14
  `;align-items:center;`,
@@ -17,7 +17,7 @@ var StyledInputWrapper = styled.span.withConfig({
17
17
  ], ({ type }) => type === "checkbox" || type === "radio" ? "nowrap" : "wrap", ({ $label }) => $label && css([`gap:5px;align-items:flex-start;align-content:flex-start;`]), ({ $fullWidth }) => fullWidthStyles($fullWidth));
18
18
  var StyledLabel = styled.label.withConfig({
19
19
  displayName: "input__StyledLabel",
20
- componentId: "sc-df1aa532-1"
20
+ componentId: "sc-f9d22714-1"
21
21
  })([
22
22
  `display:inline-block;color:`,
23
23
  `;font-size:`,
@@ -26,7 +26,7 @@ var StyledLabel = styled.label.withConfig({
26
26
  ], ({ theme }) => theme.colors.grayDark, ({ theme }) => theme.fontSizes.small.lg, ({ theme }) => theme.lineHeights.small.lg);
27
27
  var StyledInput = styled.input.withConfig({
28
28
  displayName: "input__StyledInput",
29
- componentId: "sc-df1aa532-2"
29
+ componentId: "sc-f9d22714-2"
30
30
  })([
31
31
  ``,
32
32
  `;`,
@@ -76,11 +76,11 @@ var StyledInput = styled.input.withConfig({
76
76
  `, ({ $fullWidth }) => fullWidthStyles($fullWidth));
77
77
  var StyledIconWrapper = styled.span.withConfig({
78
78
  displayName: "input__StyledIconWrapper",
79
- componentId: "sc-df1aa532-3"
79
+ componentId: "sc-f9d22714-3"
80
80
  })([`display:inline-flex;position:relative;line-height:0;min-width:fit-content;& em{display:block;border-radius:50%;background:`, `;}& svg,& em{object-fit:contain;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) scale(0.7);opacity:0;pointer-events:none;transition:all 0.3s ease;}`], ({ theme }) => theme.colors.primary);
81
81
  var StyledRadioCheckboxInput = styled.input.withConfig({
82
82
  displayName: "input__StyledRadioCheckboxInput",
83
- componentId: "sc-df1aa532-4"
83
+ componentId: "sc-f9d22714-4"
84
84
  })([
85
85
  ``,
86
86
  `;display:inline-block;background:`,
@@ -165,7 +165,7 @@ var StyledRadioCheckboxInput = styled.input.withConfig({
165
165
  });
166
166
  var StyledCustomIconWrapper = styled.span.withConfig({
167
167
  displayName: "input__StyledCustomIconWrapper",
168
- componentId: "sc-df1aa532-5"
168
+ componentId: "sc-f9d22714-5"
169
169
  })([
170
170
  `position:relative;`,
171
171
  `;& svg{position:absolute;top:50%;transform:translateY(-50%);pointer-events:none;width:24px;height:24px;object-fit:contain;color:`,
@@ -0,0 +1,10 @@
1
+ import { default as React } from 'react';
2
+ export interface ModalProps {
3
+ children: React.ReactNode;
4
+ $isOpen: boolean;
5
+ $onClose: () => void;
6
+ $title?: string;
7
+ $width?: number;
8
+ }
9
+ declare function Modal({ children, $isOpen, $onClose, $title, $width }: ModalProps): React.ReactPortal | null;
10
+ export { Modal };
package/dist/modal.js ADDED
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ "use client";
3
+ import { mq } from "./utils/theme.js";
4
+ import { styledH5, styledText } from "./utils/typography.js";
5
+ import { useOnClickOutside } from "./utils/use-on-click-outside.js";
6
+ import { Icon } from "./icon.js";
7
+ import { IconButton } from "./icon-button.js";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { useCallback, useEffect, useRef, useSyncExternalStore } from "react";
10
+ import styled, { css } from "styled-components";
11
+ import { rgba } from "polished";
12
+ import { createPortal } from "react-dom";
13
+ //#region src/lib/modal.tsx
14
+ var emptySubscribe = () => () => {};
15
+ function useIsClient() {
16
+ return useSyncExternalStore(emptySubscribe, () => true, () => false);
17
+ }
18
+ var StyledModal = styled.div.withConfig({
19
+ displayName: "modal__StyledModal",
20
+ componentId: "sc-43ca5273-0"
21
+ })([
22
+ `position:fixed;top:0;left:0;width:100%;height:100%;background:`,
23
+ `;display:flex;justify-content:center;align-items:center;z-index:1010;pointer-events:none;opacity:0;transition:all 0.3s ease;`,
24
+ ` & .modal-inner{background:`,
25
+ `;border-radius:`,
26
+ `;padding:20px;max-width:calc(100% - 40px);width:100%;margin:auto;position:relative;transform:translateY(40px);transition:all 0.3s ease;`,
27
+ ` `,
28
+ `{max-width:500px;`,
29
+ `}}`
30
+ ], ({ theme }) => rgba(theme.colors.primary, .5), ({ $isOpen }) => $isOpen && css([`opacity:1;pointer-events:all;`]), ({ theme }) => theme.colors.light, ({ theme }) => theme.spacing.radius.lg, ({ $isOpen }) => $isOpen && css([`transform:translateY(0);`]), mq("lg"), ({ $width }) => $width && css([`max-width:`, `px;`], $width));
31
+ var StyledModalClose = styled(IconButton).withConfig({
32
+ displayName: "modal__StyledModalClose",
33
+ componentId: "sc-43ca5273-1"
34
+ })([`position:absolute;top:20px;right:20px;z-index:10;`]);
35
+ var StyledModalTitle = styled.h2.withConfig({
36
+ displayName: "modal__StyledModalTitle",
37
+ componentId: "sc-43ca5273-2"
38
+ })([
39
+ `--divider-color:`,
40
+ `;margin:0 0 15px 0;padding:0 0 15px 0;color:`,
41
+ `;position:relative;`,
42
+ `;&::after{content:"";position:absolute;bottom:0;left:0;width:100%;height:1px;background:var(--divider-color);}`
43
+ ], ({ theme }) => theme.colors.grayLight, ({ theme }) => theme.colors.dark, ({ theme }) => styledH5(theme));
44
+ var StyledModalContent = styled.div.withConfig({
45
+ displayName: "modal__StyledModalContent",
46
+ componentId: "sc-43ca5273-3"
47
+ })([
48
+ `max-height:calc(100svh - 200px);overflow-y:auto;padding:5px;margin:-5px;--divider-color:`,
49
+ `;`,
50
+ `;& hr{margin:20px 0;border:none;border-bottom:solid 1px var(--divider-color);}`
51
+ ], ({ theme }) => theme.colors.grayLight, ({ theme }) => styledText(theme));
52
+ function Modal({ children, $isOpen, $onClose, $title, $width }) {
53
+ const wrapperRef = useRef(null);
54
+ const elmRef = useRef(null);
55
+ const isClient = useIsClient();
56
+ const closeModal = useCallback(() => {
57
+ $onClose();
58
+ }, [$onClose]);
59
+ useEffect(() => {
60
+ if (!$isOpen) return;
61
+ function handleKeydown(event) {
62
+ if (event.key === "Escape") {
63
+ event.preventDefault();
64
+ closeModal();
65
+ }
66
+ }
67
+ document.addEventListener("keydown", handleKeydown);
68
+ return () => document.removeEventListener("keydown", handleKeydown);
69
+ }, [$isOpen, closeModal]);
70
+ useOnClickOutside([elmRef, wrapperRef], $isOpen ? closeModal : () => {});
71
+ if (!isClient) return null;
72
+ return /*#__PURE__*/ createPortal(/*#__PURE__*/ jsx(StyledModal, {
73
+ $isOpen,
74
+ $width,
75
+ children: /*#__PURE__*/ jsxs("div", {
76
+ className: "modal-inner",
77
+ ref: wrapperRef,
78
+ children: [
79
+ /*#__PURE__*/ jsx("span", {
80
+ ref: elmRef,
81
+ children: /*#__PURE__*/ jsx(StyledModalClose, {
82
+ $size: "small",
83
+ onClick: closeModal,
84
+ className: "modal-close",
85
+ "aria-label": "Close Modal",
86
+ children: /*#__PURE__*/ jsx(Icon, { name: "X" })
87
+ })
88
+ }),
89
+ $title && /*#__PURE__*/ jsx(StyledModalTitle, { children: $title }),
90
+ /*#__PURE__*/ jsx(StyledModalContent, { children })
91
+ ]
92
+ })
93
+ }), document.body);
94
+ }
95
+ //#endregion
96
+ export { Modal };
@@ -0,0 +1,5 @@
1
+ import { default as React } from 'react';
2
+ import { InputProps } from './input';
3
+ export type PasswordProps = Omit<InputProps, "type" | "$icon" | "$iconPosition">;
4
+ declare const Password: React.ForwardRefExoticComponent<PasswordProps & React.RefAttributes<HTMLInputElement>>;
5
+ export { Password };
@@ -0,0 +1,75 @@
1
+ "use client";
2
+ "use client";
3
+ import { fullWidthStyles } from "./utils/mixins.js";
4
+ import { Icon } from "./icon.js";
5
+ import { IconButton } from "./icon-button.js";
6
+ import { Input } from "./input.js";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { forwardRef, useState } from "react";
9
+ import styled, { css } from "styled-components";
10
+ //#region src/lib/password.tsx
11
+ var passwordSizes = {
12
+ small: {
13
+ height: 40,
14
+ inset: 8,
15
+ button: 24
16
+ },
17
+ default: {
18
+ height: 50,
19
+ inset: 11,
20
+ button: 28
21
+ },
22
+ big: {
23
+ height: 60,
24
+ inset: 16,
25
+ button: 28
26
+ }
27
+ };
28
+ var StyledPassword = styled.span.withConfig({
29
+ displayName: "password__StyledPassword",
30
+ componentId: "sc-b3beabaa-0"
31
+ })([
32
+ `position:relative;display:inline-flex;& input{padding-right:`,
33
+ `;}`,
34
+ ``
35
+ ], ({ $size }) => {
36
+ const { inset, button } = passwordSizes[$size ?? "default"];
37
+ return `${inset + button + 10}px`;
38
+ }, ({ $fullWidth }) => fullWidthStyles($fullWidth));
39
+ var StyledPasswordReveal = styled.span.withConfig({
40
+ displayName: "password__StyledPasswordReveal",
41
+ componentId: "sc-b3beabaa-1"
42
+ })([`position:absolute;bottom:0;display:flex;align-items:center;`, ``], ({ $size }) => {
43
+ const { height, inset } = passwordSizes[$size ?? "default"];
44
+ return css([
45
+ `right:`,
46
+ `px;height:`,
47
+ `px;`
48
+ ], inset, height);
49
+ });
50
+ function LocalPassword({ ...props }, ref) {
51
+ const [show, setShow] = useState(false);
52
+ return /*#__PURE__*/ jsxs(StyledPassword, {
53
+ $size: props.$size,
54
+ $fullWidth: props.$fullWidth,
55
+ children: [/*#__PURE__*/ jsx(Input, {
56
+ ...props,
57
+ type: show ? "text" : "password",
58
+ ref
59
+ }), /*#__PURE__*/ jsx(StyledPasswordReveal, {
60
+ $size: props.$size,
61
+ children: /*#__PURE__*/ jsx(IconButton, {
62
+ $size: props.$size === "small" ? "small" : "default",
63
+ $error: props.$error,
64
+ "aria-label": show ? "Hide password" : "Show password",
65
+ "aria-pressed": show,
66
+ title: show ? "Hide password" : "Show password",
67
+ onClick: () => setShow((prev) => !prev),
68
+ children: /*#__PURE__*/ jsx(Icon, { name: show ? "EyeOff" : "Eye" })
69
+ })
70
+ })]
71
+ });
72
+ }
73
+ var Password = /*#__PURE__*/ forwardRef(LocalPassword);
74
+ //#endregion
75
+ export { Password };