@optigrit/optigrit-ui 0.0.1 → 0.0.3

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/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # @optigrit/optigrit-ui
2
+
3
+ UI component library for Optigrit apps (React + Tailwind CSS).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @optigrit/optigrit-ui
9
+ ```
10
+
11
+ Peer dependencies (install in your app):
12
+
13
+ ```bash
14
+ npm install react react-dom tailwindcss
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ Import components from the package root or subpaths:
20
+
21
+ ```tsx
22
+ import { /* components */ } from "@optigrit/optigrit-ui";
23
+ import { /* theme helpers */ } from "@optigrit/optigrit-ui/theme";
24
+ import { /* hooks */ } from "@optigrit/optigrit-ui/hooks";
25
+ ```
26
+
27
+ Tailwind preset:
28
+
29
+ ```js
30
+ // tailwind.config.js
31
+ import preset from "@optigrit/optigrit-ui/preset";
32
+
33
+ export default {
34
+ presets: [preset],
35
+ content: [
36
+ "./node_modules/@optigrit/optigrit-ui/**/*.{js,jsx,ts,tsx}",
37
+ "./src/**/*.{js,jsx,ts,tsx}",
38
+ ],
39
+ };
40
+ ```
41
+
42
+ Base styles (optional): copy or import `index.css` from the package as needed.
43
+
44
+ ## CLI (`init`)
45
+
46
+ After installing the package:
47
+
48
+ ```bash
49
+ npx optigrit-ui init
50
+ ```
51
+
52
+ (or `npx @optigrit/optigrit-ui init`)
53
+
54
+ This wires Tailwind to use the preset and copies starter CSS when possible.
55
+
56
+ ## Scripts (development)
57
+
58
+ | Script | Description |
59
+ | --- | --- |
60
+ | `npm run build` | Production bundle (`tsup` → `dist/`) |
61
+ | `npm run lint` | Typecheck (`tsc`) |
62
+ | `npm run storybook` | Storybook dev server |
63
+
64
+ ## License
65
+
66
+ ISC
@@ -8,6 +8,7 @@ type PopoverProps = HTMLAttributes<HTMLDivElement> & {
8
8
  open?: boolean;
9
9
  onClose?: () => void;
10
10
  onOpen?: (node: HTMLDivElement) => void;
11
+ closeOnClickOutside?: boolean;
11
12
  };
12
13
 
13
14
  type InputProps = {
@@ -40,6 +40,7 @@ function calculatePopoverStyle(container, defaultPosition) {
40
40
  }
41
41
 
42
42
  // src/core/Popover/Popover.tsx
43
+ import { createPortal } from "react-dom";
43
44
  import { jsx, jsxs } from "react/jsx-runtime";
44
45
  function Popover(props) {
45
46
  const {
@@ -49,6 +50,7 @@ function Popover(props) {
49
50
  onClose,
50
51
  position: _position = "bottom-center",
51
52
  onOpen,
53
+ closeOnClickOutside = true,
52
54
  ...popoverProps
53
55
  } = props;
54
56
  const popoverRef = useRef(null);
@@ -120,37 +122,43 @@ function Popover(props) {
120
122
  if (open) showPopover();
121
123
  else hidePopover();
122
124
  }, [open]);
123
- return /* @__PURE__ */ jsxs(Fragment, { children: [
124
- /* @__PURE__ */ jsx(
125
- "div",
126
- {
127
- className: "fixed w-[100dvw] h-[100dvh] left-0 top-0",
128
- style: { display: open ? "block" : "none" },
129
- onClick: handleClickOutside
130
- }
131
- ),
132
- /* @__PURE__ */ jsx(
133
- "div",
134
- {
135
- ...popoverProps,
136
- ref: popoverRef,
137
- style: {
138
- display: "flex",
139
- position: "fixed",
140
- transition: "all 200ms",
141
- opacity: 0,
142
- scale: 0.8,
143
- ...popoverProps.style
144
- },
145
- children
146
- }
147
- )
148
- ] });
125
+ if (!targetRef.current) return null;
126
+ return createPortal(
127
+ /* @__PURE__ */ jsxs(Fragment, { children: [
128
+ /* @__PURE__ */ jsx(Show, { when: !!closeOnClickOutside, children: /* @__PURE__ */ jsx(
129
+ "div",
130
+ {
131
+ className: "fixed w-[100dvw] h-[100dvh] left-0 top-0 z-[1] bg-red-600/10",
132
+ style: { display: open ? "block" : "none" },
133
+ onClick: handleClickOutside
134
+ }
135
+ ) }),
136
+ /* @__PURE__ */ jsx(
137
+ "div",
138
+ {
139
+ ...popoverProps,
140
+ ref: popoverRef,
141
+ style: {
142
+ display: "flex",
143
+ position: "fixed",
144
+ transition: "all 200ms",
145
+ opacity: 0,
146
+ scale: 0.8,
147
+ zIndex: 2,
148
+ ...popoverProps.style
149
+ },
150
+ children
151
+ }
152
+ )
153
+ ] }),
154
+ document.body
155
+ );
149
156
  }
150
157
 
151
158
  // src/shared/utils/helper.ts
152
- function cn(...classes) {
153
- return classes.filter(Boolean).join(" ");
159
+ import { twMerge } from "tailwind-merge";
160
+ function cn(...inputs) {
161
+ return twMerge(inputs.filter(Boolean).join(" "));
154
162
  }
155
163
 
156
164
  // src/core/Input/Input.tsx
@@ -164,10 +172,10 @@ var Input = forwardRef((props, ref) => {
164
172
  required,
165
173
  fullWidth = false,
166
174
  labelShrink = false,
167
- bgColor = "white",
168
- textColor = "black",
169
- borderColor = "black",
170
- primaryColor = "royalblue",
175
+ bgColor = "var(--bg, white)",
176
+ textColor = "var(--text, black)",
177
+ borderColor = "var(--border, black)",
178
+ primaryColor = "var(--primary, royalblue)",
171
179
  inputContainerProps = {},
172
180
  ...inputProps
173
181
  } = props;
@@ -266,8 +274,98 @@ var Input = forwardRef((props, ref) => {
266
274
  );
267
275
  });
268
276
 
277
+ // src/core/Ripple/index.tsx
278
+ import { forwardRef as forwardRef2, useImperativeHandle, useCallback, useRef as useRef3 } from "react";
279
+ import { jsx as jsx3 } from "react/jsx-runtime";
280
+ var Ripple = forwardRef2(
281
+ ({ color = "rgba(255, 255, 255, 0.3)", duration = 600 }, ref) => {
282
+ const containerRef = useRef3(null);
283
+ const addRipple = useCallback(
284
+ (event) => {
285
+ const container = containerRef.current;
286
+ if (!container) return;
287
+ const rect = container.getBoundingClientRect();
288
+ const diameter = Math.max(rect.width, rect.height);
289
+ const radius = diameter / 2;
290
+ const circle = document.createElement("span");
291
+ circle.style.position = "absolute";
292
+ circle.style.width = `${diameter}px`;
293
+ circle.style.height = `${diameter}px`;
294
+ circle.style.left = `${event.clientX - rect.left - radius}px`;
295
+ circle.style.top = `${event.clientY - rect.top - radius}px`;
296
+ circle.style.borderRadius = "9999px";
297
+ circle.style.pointerEvents = "none";
298
+ circle.style.backgroundColor = color;
299
+ container.appendChild(circle);
300
+ const anim = circle.animate(
301
+ [
302
+ { transform: "scale(0)", opacity: "1" },
303
+ { transform: "scale(4)", opacity: "0" }
304
+ ],
305
+ { duration, easing: "linear" }
306
+ );
307
+ anim.onfinish = () => circle.remove();
308
+ },
309
+ [color, duration]
310
+ );
311
+ useImperativeHandle(ref, () => ({
312
+ addRipple
313
+ }));
314
+ return /* @__PURE__ */ jsx3(
315
+ "span",
316
+ {
317
+ ref: containerRef,
318
+ className: "absolute inset-0 overflow-hidden pointer-events-none",
319
+ "aria-hidden": "true"
320
+ }
321
+ );
322
+ }
323
+ );
324
+ Ripple.displayName = "Ripple";
325
+
326
+ // src/core/Spinner/index.tsx
327
+ import { jsx as jsx4 } from "react/jsx-runtime";
328
+ var colorClasses = {
329
+ primary: "text-primary",
330
+ secondary: "text-secondary",
331
+ error: "text-error",
332
+ info: "text-info",
333
+ success: "text-success",
334
+ warning: "text-warning",
335
+ inherit: "text-inherit"
336
+ };
337
+ function Spinner({
338
+ size = 40,
339
+ thickness = 3.6,
340
+ color = "primary",
341
+ className = ""
342
+ }) {
343
+ const sizeStyle = typeof size === "number" ? `${size}px` : size;
344
+ return /* @__PURE__ */ jsx4(
345
+ "div",
346
+ {
347
+ role: "progressbar",
348
+ className: `inline-block animate-circular-rotate ${colorClasses[color]} ${className}`,
349
+ style: { width: sizeStyle, height: sizeStyle },
350
+ children: /* @__PURE__ */ jsx4("svg", { viewBox: "22 22 44 44", className: "block w-full h-full", children: /* @__PURE__ */ jsx4(
351
+ "circle",
352
+ {
353
+ className: "animate-circular-dash",
354
+ cx: "44",
355
+ cy: "44",
356
+ r: 20,
357
+ fill: "none",
358
+ stroke: "currentColor",
359
+ strokeWidth: thickness,
360
+ strokeLinecap: "round"
361
+ }
362
+ ) })
363
+ }
364
+ );
365
+ }
366
+
269
367
  // src/core/ShowWithAnimation/index.tsx
270
- import { useLayoutEffect as useLayoutEffect3, useRef as useRef3, useState as useState2 } from "react";
368
+ import { useLayoutEffect as useLayoutEffect3, useRef as useRef4, useState as useState2 } from "react";
271
369
 
272
370
  // src/core/ShowWithAnimation/const.ts
273
371
  var defaultAnimationStyle = {
@@ -304,7 +402,7 @@ var defaultAnimationStyle = {
304
402
  };
305
403
 
306
404
  // src/core/ShowWithAnimation/index.tsx
307
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
405
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
308
406
  function ShowWithAnimation(props) {
309
407
  const {
310
408
  when,
@@ -312,11 +410,12 @@ function ShowWithAnimation(props) {
312
410
  containerProps,
313
411
  animationStyle,
314
412
  otherwise = null,
315
- removeOnHide = false,
413
+ removeOnHide: _removeOnHide = false,
316
414
  animationType = "fade",
317
415
  animationDuration = 300,
318
416
  ...wrapperProps
319
417
  } = props;
418
+ const removeOnHide = _removeOnHide === void 0 || _removeOnHide;
320
419
  if (animationStyle) {
321
420
  if (!animationStyle.children.to) {
322
421
  animationStyle.children.to = animationStyle.children.from;
@@ -329,20 +428,21 @@ function ShowWithAnimation(props) {
329
428
  }
330
429
  }
331
430
  const defaultAnimationStyle2 = (() => {
332
- const animationStyle2 = defaultAnimationStyle[animationType];
333
- if (!animationStyle2.children.to) {
334
- animationStyle2.children.to = animationStyle2.children.from;
431
+ if (animationStyle) return animationStyle;
432
+ const defaultAnimationStyle3 = defaultAnimationStyle[animationType];
433
+ if (!defaultAnimationStyle3.children.to) {
434
+ defaultAnimationStyle3.children.to = defaultAnimationStyle3.children.from;
335
435
  }
336
- if (!animationStyle2.otherwise) {
337
- animationStyle2.otherwise = animationStyle2.children;
436
+ if (!defaultAnimationStyle3.otherwise) {
437
+ defaultAnimationStyle3.otherwise = defaultAnimationStyle3.children;
338
438
  }
339
- if (!animationStyle2.otherwise.to) {
340
- animationStyle2.otherwise.to = animationStyle2.otherwise.from;
439
+ if (!defaultAnimationStyle3.otherwise.to) {
440
+ defaultAnimationStyle3.otherwise.to = defaultAnimationStyle3.otherwise.from;
341
441
  }
342
- return animationStyle2;
442
+ return defaultAnimationStyle3;
343
443
  })();
344
- const childrenContainer = useRef3(null);
345
- const otherwiseContainer = useRef3(null);
444
+ const childrenContainer = useRef4(null);
445
+ const otherwiseContainer = useRef4(null);
346
446
  const [isChildrenVisible, setIsChildrenVisible] = useState2(when);
347
447
  const [isOtherwiseVisible, setIsOtherwiseVisible] = useState2(!when);
348
448
  function handleShow() {
@@ -413,9 +513,8 @@ function ShowWithAnimation(props) {
413
513
  {
414
514
  ...containerProps,
415
515
  className: cn("relative flex items-center justify-center", containerProps?.className),
416
- style: { ...containerProps?.style, position: "relative" },
417
516
  children: [
418
- isChildrenVisible ? /* @__PURE__ */ jsx3(
517
+ isChildrenVisible ? /* @__PURE__ */ jsx5(
419
518
  "div",
420
519
  {
421
520
  ...wrapperProps,
@@ -430,7 +529,7 @@ function ShowWithAnimation(props) {
430
529
  children
431
530
  }
432
531
  ) : null,
433
- otherwise && isOtherwiseVisible ? /* @__PURE__ */ jsx3(
532
+ otherwise && isOtherwiseVisible ? /* @__PURE__ */ jsx5(
434
533
  "div",
435
534
  {
436
535
  ...wrapperProps,
@@ -460,6 +559,8 @@ export {
460
559
  Popover,
461
560
  cn,
462
561
  Input,
562
+ Ripple,
563
+ Spinner,
463
564
  ShowWithAnimation,
464
565
  Show
465
566
  };
@@ -1,24 +1,35 @@
1
1
  import * as react from 'react';
2
- import { ButtonHTMLAttributes, ReactNode, HTMLAttributes, RefObject } from 'react';
2
+ import react__default, { ButtonHTMLAttributes, ReactNode, HTMLAttributes, RefObject, TableHTMLAttributes } from 'react';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
- import { P as PopoverProps, a as InputProps } from '../Input-CL3wQvR_.js';
4
+ import { P as PopoverProps, a as InputProps } from '../Input-CWxBHfX8.js';
5
5
 
6
- type ButtonVariant = "primary" | "secondary" | "outline" | "ghost" | "destructive" | "link";
6
+ type ButtonVariant = "contained" | "outlined" | "soft" | "text";
7
+ type ButtonColor = "primary" | "secondary" | "error" | "success" | "warning" | "info";
7
8
  type ButtonSize = "xs" | "sm" | "md" | "lg" | "xl";
8
9
  type ButtonRoundness = "none" | "sm" | "md" | "lg" | "full";
9
10
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
10
11
  variant?: ButtonVariant;
12
+ color?: ButtonColor;
11
13
  size?: ButtonSize;
12
14
  roundness?: ButtonRoundness;
13
15
  fullWidth?: boolean;
14
16
  loading?: boolean;
15
17
  leftIcon?: ReactNode;
16
18
  rightIcon?: ReactNode;
17
- iconOnly?: boolean;
18
19
  disableRipple?: boolean;
19
20
  }
20
21
  declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
21
22
 
23
+ interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
24
+ variant?: ButtonVariant;
25
+ color?: ButtonColor;
26
+ size?: ButtonSize;
27
+ roundness?: ButtonRoundness;
28
+ loading?: boolean;
29
+ disableRipple?: boolean;
30
+ }
31
+ declare const IconButton: react.ForwardRefExoticComponent<IconButtonProps & react.RefAttributes<HTMLButtonElement>>;
32
+
22
33
  type SIZE = "xs" | "sm" | "md" | "lg" | "xl";
23
34
 
24
35
  type TooltipProps = HTMLAttributes<HTMLDivElement> & {
@@ -66,4 +77,96 @@ type MultiSelectProps = {
66
77
  } & Omit<InputFieldProps, 'readOnly' | 'value' | 'onChange' | 'onChangeValue'>;
67
78
  declare function MultiSelect(props: MultiSelectProps): react_jsx_runtime.JSX.Element;
68
79
 
69
- export { Button, type ButtonProps, type ButtonRoundness, type ButtonSize, type ButtonVariant, InputField, type InputFieldProps, MultiSelect, type MultiSelectProps, Select, type SelectProps, Tooltip, type TooltipProps };
80
+ interface TableProps extends TableHTMLAttributes<HTMLTableElement> {
81
+ stickyHeader?: boolean;
82
+ size?: "small" | "medium";
83
+ }
84
+ declare const Table: react.ForwardRefExoticComponent<TableProps & react.RefAttributes<HTMLTableElement>>;
85
+
86
+ interface TableBodyProps extends HTMLAttributes<HTMLTableSectionElement> {
87
+ }
88
+ declare const TableBody: react.ForwardRefExoticComponent<TableBodyProps & react.RefAttributes<HTMLTableSectionElement>>;
89
+
90
+ interface TableCellProps extends HTMLAttributes<HTMLTableCellElement> {
91
+ align?: "left" | "center" | "right" | "justify" | "inherit";
92
+ padding?: "normal" | "none" | "checkbox";
93
+ variant?: "head" | "body" | "footer";
94
+ component?: "td" | "th";
95
+ }
96
+ declare const TableCell: react.ForwardRefExoticComponent<TableCellProps & react.RefAttributes<HTMLTableCellElement>>;
97
+
98
+ interface TableContainerProps extends HTMLAttributes<HTMLDivElement> {
99
+ }
100
+ declare const TableContainer: react.ForwardRefExoticComponent<TableContainerProps & react.RefAttributes<HTMLDivElement>>;
101
+
102
+ interface TableFooterProps extends HTMLAttributes<HTMLTableSectionElement> {
103
+ }
104
+ declare const TableFooter: react.ForwardRefExoticComponent<TableFooterProps & react.RefAttributes<HTMLTableSectionElement>>;
105
+
106
+ interface TableHeadProps extends HTMLAttributes<HTMLTableSectionElement> {
107
+ }
108
+ declare const TableHead: react.ForwardRefExoticComponent<TableHeadProps & react.RefAttributes<HTMLTableSectionElement>>;
109
+
110
+ interface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {
111
+ hover?: boolean;
112
+ selected?: boolean;
113
+ }
114
+ declare const TableRow: react.ForwardRefExoticComponent<TableRowProps & react.RefAttributes<HTMLTableRowElement>>;
115
+
116
+ type DialogProps = {
117
+ open: boolean;
118
+ onClose?: () => void;
119
+ children?: react__default.ReactNode;
120
+ backdropClose?: boolean;
121
+ className?: string;
122
+ closeOnEsc?: boolean;
123
+ animationDuration?: number;
124
+ size?: SIZE | "full" | "auto";
125
+ };
126
+ declare function Dialog(props: DialogProps): react__default.ReactPortal | null;
127
+
128
+ type DialogHeaderProps = HTMLAttributes<HTMLDivElement> & {
129
+ title?: string;
130
+ };
131
+ declare function DialogHeader(props: DialogHeaderProps): react_jsx_runtime.JSX.Element;
132
+
133
+ declare function DialogFooter(props: HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
134
+
135
+ declare function DialogContent(props: HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
136
+
137
+ type DrawerProps = {
138
+ open: boolean;
139
+ onClose?: () => void;
140
+ children?: react__default.ReactNode;
141
+ backdropClose?: boolean;
142
+ className?: string;
143
+ closeOnEsc?: boolean;
144
+ animationDuration?: number;
145
+ side?: 'right' | 'left' | 'top' | 'bottom';
146
+ size?: SIZE | number;
147
+ rounded?: number;
148
+ };
149
+ declare function Drawer(props: DrawerProps): react__default.ReactPortal | null;
150
+
151
+ type DrawerContentProps = {
152
+ children?: react__default.ReactNode;
153
+ className?: string;
154
+ style?: react__default.CSSProperties;
155
+ };
156
+ declare function DrawerContent({ children, className, style }: DrawerContentProps): react_jsx_runtime.JSX.Element;
157
+
158
+ type DrawerHeaderProps = {
159
+ children?: react__default.ReactNode;
160
+ className?: string;
161
+ style?: react__default.CSSProperties;
162
+ };
163
+ declare function DrawerHeader({ children, className, style }: DrawerHeaderProps): react_jsx_runtime.JSX.Element;
164
+
165
+ type DrawerFooterProps = {
166
+ children?: react__default.ReactNode;
167
+ className?: string;
168
+ style?: react__default.CSSProperties;
169
+ };
170
+ declare function DrawerFooter({ children, className, style }: DrawerFooterProps): react_jsx_runtime.JSX.Element;
171
+
172
+ export { Button, type ButtonColor, type ButtonProps, type ButtonRoundness, type ButtonSize, type ButtonVariant, Dialog, DialogContent, DialogFooter, DialogHeader, type DialogProps, Drawer, DrawerContent, DrawerFooter, DrawerHeader, type DrawerProps, IconButton, type IconButtonProps, InputField, type InputFieldProps, MultiSelect, type MultiSelectProps, Select, type SelectProps, Table, TableBody, type TableBodyProps, TableCell, type TableCellProps, TableContainer, type TableContainerProps, TableFooter, type TableFooterProps, TableHead, type TableHeadProps, type TableProps, TableRow, type TableRowProps, Tooltip, type TooltipProps };