@axzydev/axzy_ui_system 1.2.16 → 1.3.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/dist/index.cjs +3349 -1457
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.cts +719 -54
- package/dist/index.d.ts +719 -54
- package/dist/index.js +3283 -1387
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/App.tsx +32 -0
- package/src/components/atoms/badget/badget.tsx +2 -4
- package/src/components/atoms/chip/chip.doc.mdx +47 -0
- package/src/components/atoms/chip/chip.props.ts +32 -0
- package/src/components/atoms/chip/chip.stories.tsx +64 -0
- package/src/components/atoms/chip/chip.tsx +112 -0
- package/src/components/atoms/grid/grid.tsx +1 -2
- package/src/components/molecules/accordion/accordion.doc.mdx +47 -0
- package/src/components/molecules/accordion/accordion.props.ts +35 -0
- package/src/components/molecules/accordion/accordion.stories.tsx +68 -0
- package/src/components/molecules/accordion/accordion.tsx +123 -0
- package/src/components/molecules/calendar/calendar.doc.mdx +2 -1
- package/src/components/molecules/calendar/calendar.tsx +102 -24
- package/src/components/molecules/chip-input/chip-input.doc.mdx +44 -0
- package/src/components/molecules/chip-input/chip-input.props.ts +42 -0
- package/src/components/molecules/chip-input/chip-input.stories.tsx +52 -0
- package/src/components/molecules/chip-input/chip-input.tsx +205 -0
- package/src/components/molecules/date-picker/datePicker.tsx +45 -56
- package/src/components/molecules/dropdown-menu/dropdown-menu.doc.mdx +46 -0
- package/src/components/molecules/dropdown-menu/dropdown-menu.props.ts +41 -0
- package/src/components/molecules/dropdown-menu/dropdown-menu.stories.tsx +41 -0
- package/src/components/molecules/dropdown-menu/dropdown-menu.tsx +219 -0
- package/src/components/molecules/field/field.doc.mdx +43 -0
- package/src/components/molecules/field/field.props.ts +23 -0
- package/src/components/molecules/field/field.stories.tsx +42 -0
- package/src/components/molecules/field/field.tsx +54 -0
- package/src/components/molecules/masked-input/masked-input.doc.mdx +78 -0
- package/src/components/molecules/masked-input/masked-input.props.ts +58 -0
- package/src/components/molecules/masked-input/masked-input.stories.tsx +126 -0
- package/src/components/molecules/masked-input/masked-input.tsx +244 -0
- package/src/components/molecules/multi-select/multi-select.doc.mdx +55 -0
- package/src/components/molecules/multi-select/multi-select.props.ts +65 -0
- package/src/components/molecules/multi-select/multi-select.stories.tsx +59 -0
- package/src/components/molecules/multi-select/multi-select.tsx +386 -0
- package/src/components/molecules/search-select/search-select.doc.mdx +5 -0
- package/src/components/molecules/search-select/search-select.props.ts +10 -1
- package/src/components/molecules/search-select/search-select.stories.tsx +18 -0
- package/src/components/molecules/search-select/search-select.tsx +102 -28
- package/src/components/molecules/time-picker/timePicker.tsx +14 -26
- package/src/components/molecules/wysiwyg/wysiwyg.props.ts +51 -0
- package/src/components/molecules/wysiwyg/wysiwyg.stories.tsx +95 -0
- package/src/components/molecules/wysiwyg/wysiwyg.tsx +609 -0
- package/src/components/organisms/form-builder/fieldRenderer.tsx +144 -27
- package/src/components/organisms/form-builder/formBuilder.context.tsx +77 -15
- package/src/components/organisms/form-builder/formBuilder.doc.mdx +213 -86
- package/src/components/organisms/form-builder/formBuilder.props.ts +118 -36
- package/src/components/organisms/form-builder/formBuilder.stories.tsx +694 -96
- package/src/components/organisms/form-builder/formBuilder.tsx +152 -69
- package/src/components/organisms/form-builder/useFormBuilder.ts +59 -21
- package/src/hooks/useFloatingPanel.ts +100 -0
- package/src/index.ts +26 -4
- package/src/showcases/DataShowcases.tsx +76 -0
- package/src/showcases/FormShowcases.tsx +574 -10
- package/src/showcases/HomeShowcase.tsx +6 -6
- package/src/showcases/NavigationShowcases.tsx +72 -2
- package/src/showcases/StructureShowcases.tsx +64 -0
- package/src/types/chip.types.ts +13 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import clsx from "clsx";
|
|
2
2
|
import React, { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
3
4
|
import { FaClock } from "react-icons/fa";
|
|
4
5
|
import ITInput from "@/components/atoms/input/input";
|
|
5
6
|
import ITButton from "@/components/atoms/button/button";
|
|
6
7
|
import useClickOutside from "@/hooks/useClickOutside";
|
|
8
|
+
import { useFloatingPanel } from "@/hooks/useFloatingPanel";
|
|
7
9
|
import { theme } from "@/theme/theme";
|
|
8
10
|
import { ITTimePickerProps } from "./timePicker.props";
|
|
9
11
|
import ITText from "@/components/atoms/text/text";
|
|
@@ -48,13 +50,18 @@ export default function ITTimePicker({
|
|
|
48
50
|
const [isOpen, setIsOpen] = useState(false);
|
|
49
51
|
const [inputValue, setInputValue] = useState(value || "");
|
|
50
52
|
const [isValidTime, setIsValidTime] = useState(true);
|
|
51
|
-
const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0 });
|
|
52
53
|
|
|
53
54
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
54
|
-
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
55
55
|
const hoursRef = useRef<HTMLDivElement>(null);
|
|
56
56
|
const minutesRef = useRef<HTMLDivElement>(null);
|
|
57
57
|
|
|
58
|
+
// Dropdown position (rendered in a portal so it escapes overflow/transform ancestors).
|
|
59
|
+
const { panelRef: dropdownRef, style: panelStyle } = useFloatingPanel(
|
|
60
|
+
wrapperRef,
|
|
61
|
+
isOpen && !disabled,
|
|
62
|
+
{ estimatedHeight: 300, matchWidth: false }
|
|
63
|
+
);
|
|
64
|
+
|
|
58
65
|
useClickOutside(dropdownRef, () => {
|
|
59
66
|
// Only close if it's currently open to avoid setting state unnecessarily
|
|
60
67
|
if (isOpen) {
|
|
@@ -76,23 +83,7 @@ export default function ITTimePicker({
|
|
|
76
83
|
setInputValue(value || "");
|
|
77
84
|
}, [value]);
|
|
78
85
|
|
|
79
|
-
const calculateDropdownPosition = () => {
|
|
80
|
-
if (wrapperRef.current) {
|
|
81
|
-
const inputRect = wrapperRef.current.getBoundingClientRect();
|
|
82
|
-
const dropdownHeight = 280; // approximate height of the time picker dropdown
|
|
83
|
-
const viewportHeight = window.innerHeight;
|
|
84
|
-
|
|
85
|
-
let top = inputRect.bottom + 4;
|
|
86
|
-
if (inputRect.bottom + dropdownHeight > viewportHeight) {
|
|
87
|
-
top = inputRect.top - dropdownHeight - 4;
|
|
88
|
-
}
|
|
89
86
|
|
|
90
|
-
setDropdownPosition({
|
|
91
|
-
top,
|
|
92
|
-
left: inputRect.left,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
87
|
|
|
97
88
|
const validateTime = (timeString: string) => {
|
|
98
89
|
const regex = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
@@ -210,7 +201,6 @@ export default function ITTimePicker({
|
|
|
210
201
|
<FaClock
|
|
211
202
|
onClick={() => {
|
|
212
203
|
if (!disabled) {
|
|
213
|
-
calculateDropdownPosition();
|
|
214
204
|
setIsOpen(!isOpen);
|
|
215
205
|
}
|
|
216
206
|
}}
|
|
@@ -224,14 +214,11 @@ export default function ITTimePicker({
|
|
|
224
214
|
}
|
|
225
215
|
/>
|
|
226
216
|
|
|
227
|
-
{isOpen && !disabled && (
|
|
217
|
+
{isOpen && !disabled && createPortal(
|
|
228
218
|
<div
|
|
229
219
|
ref={dropdownRef}
|
|
230
|
-
className="
|
|
231
|
-
style={
|
|
232
|
-
top: `${dropdownPosition.top}px`,
|
|
233
|
-
left: `${dropdownPosition.left}px`,
|
|
234
|
-
}}
|
|
220
|
+
className="bg-white border border-secondary-100 shadow-xl rounded-xl w-64 overflow-hidden flex flex-col animate-in fade-in zoom-in-95 duration-200 origin-top it-timepicker-dropdown"
|
|
221
|
+
style={panelStyle}
|
|
235
222
|
>
|
|
236
223
|
<div className="flex bg-secondary-50 border-b border-secondary-100 text-xs font-semibold text-secondary-500 uppercase tracking-wider">
|
|
237
224
|
<ITText as="div" className="flex-1 text-center py-2 border-r border-secondary-100">
|
|
@@ -331,7 +318,8 @@ export default function ITTimePicker({
|
|
|
331
318
|
<ITText as="span">Aceptar</ITText>
|
|
332
319
|
</ITButton>
|
|
333
320
|
</div>
|
|
334
|
-
</div
|
|
321
|
+
</div>,
|
|
322
|
+
document.body
|
|
335
323
|
)}
|
|
336
324
|
</div>
|
|
337
325
|
);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { SizesTypes } from "@/types/sizes.types";
|
|
2
|
+
|
|
3
|
+
/** Toolbar actions supported by ITWysiwyg. */
|
|
4
|
+
export type ToolbarAction =
|
|
5
|
+
| "bold"
|
|
6
|
+
| "italic"
|
|
7
|
+
| "underline"
|
|
8
|
+
| "highlight"
|
|
9
|
+
| "ul"
|
|
10
|
+
| "ol"
|
|
11
|
+
| "clear";
|
|
12
|
+
|
|
13
|
+
/** Available formatting tools. Every action maps to a toolbar button with an icon and tooltip. */
|
|
14
|
+
export const toolbarActions: ToolbarAction[] = [
|
|
15
|
+
"bold",
|
|
16
|
+
"italic",
|
|
17
|
+
"underline",
|
|
18
|
+
"highlight",
|
|
19
|
+
"ul",
|
|
20
|
+
"ol",
|
|
21
|
+
"clear",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export interface ITWysiwygProps {
|
|
25
|
+
/** Controlled HTML value rendered inside the editor. Overrides the visible content only while the editor is not focused (avoids caret jumps). */
|
|
26
|
+
value?: string;
|
|
27
|
+
/** Callback fired with the editor's HTML whenever the content changes. */
|
|
28
|
+
onChange?: (html: string) => void;
|
|
29
|
+
/** Label text rendered above the editor. */
|
|
30
|
+
label?: string;
|
|
31
|
+
/** Placeholder text shown when the editor is empty. */
|
|
32
|
+
placeholder?: string;
|
|
33
|
+
/** Validation error message displayed below the editor. */
|
|
34
|
+
error?: string;
|
|
35
|
+
/** Disables the editor and toolbar when true. @default false */
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
/** Renders content in read-only mode (not editable, toolbar disabled). @default false */
|
|
38
|
+
readOnly?: boolean;
|
|
39
|
+
/** Name attribute for form submission and label association via `htmlFor`. */
|
|
40
|
+
name?: string;
|
|
41
|
+
/** Editor size: controls padding and font size. Valid values: `"sm"`, `"md"`, `"lg"`. @default "md" */
|
|
42
|
+
size?: SizesTypes;
|
|
43
|
+
/** Minimum height in pixels of the editable area. @default 128 */
|
|
44
|
+
minHeight?: number;
|
|
45
|
+
/** Background color used by the marker tool (yellow highlight). @default "#fde68a" */
|
|
46
|
+
highlightColor?: string;
|
|
47
|
+
/** Subset of toolbar actions to render. @default all actions */
|
|
48
|
+
toolbar?: ToolbarAction[];
|
|
49
|
+
/** Additional CSS classes for the wrapper. */
|
|
50
|
+
className?: string;
|
|
51
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import ITWysiwyg from '@/components/molecules/wysiwyg/wysiwyg';
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: 'Components/Form/ITWysiwyg',
|
|
7
|
+
component: ITWysiwyg,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
},
|
|
11
|
+
argTypes: {
|
|
12
|
+
size: {
|
|
13
|
+
control: 'select',
|
|
14
|
+
options: ['sm', 'md', 'lg'],
|
|
15
|
+
},
|
|
16
|
+
toolbar: {
|
|
17
|
+
control: 'select',
|
|
18
|
+
options: [
|
|
19
|
+
['bold', 'italic', 'underline', 'highlight', 'ul', 'ol', 'clear'],
|
|
20
|
+
['bold', 'italic', 'underline'],
|
|
21
|
+
['ul', 'ol'],
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
} satisfies Meta<typeof ITWysiwyg>;
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
type Story = StoryObj<typeof meta>;
|
|
29
|
+
|
|
30
|
+
export const Default: Story = {
|
|
31
|
+
args: {
|
|
32
|
+
placeholder: 'Escribe algo...',
|
|
33
|
+
minHeight: 140,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const WithLabel: Story = {
|
|
38
|
+
args: {
|
|
39
|
+
label: 'Descripción',
|
|
40
|
+
placeholder: 'Texto libre...',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const WithValue: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
value: '<div>Texto con <strong>negrita</strong>, <em>itálica</em> y <u>subrayado</u>.</div><div><mark style="background-color:#fde68a">Con marcador</mark> y:</div><ul><li>Elemento uno</li><li>Elemento dos</li></ul>',
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const Disabled: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
disabled: true,
|
|
53
|
+
value: '<div>Contenido bloqueado para edición.</div>',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const ReadOnly: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
readOnly: true,
|
|
60
|
+
label: 'Vista previa',
|
|
61
|
+
value: '<div>Solo lectura, sin toolbar activo.</div>',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const WithError: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
label: 'Descripción',
|
|
68
|
+
error: 'Este campo es obligatorio.',
|
|
69
|
+
value: '',
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const CustomHighlight: Story = {
|
|
74
|
+
args: {
|
|
75
|
+
highlightColor: '#a7f3d0',
|
|
76
|
+
label: 'Marcador verde',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const LiveValue: Story = {
|
|
81
|
+
render: (args) => {
|
|
82
|
+
const [html, setHtml] = useState<string>(
|
|
83
|
+
'<div>Edita aquí y mira el HTML generado abajo.</div>'
|
|
84
|
+
);
|
|
85
|
+
return (
|
|
86
|
+
<div className="w-96 space-y-4">
|
|
87
|
+
<ITWysiwyg {...args} value={html} onChange={setHtml} />
|
|
88
|
+
<pre className="max-h-40 overflow-auto rounded-lg bg-slate-950 p-3 text-[10px] text-emerald-300">
|
|
89
|
+
<code>{html}</code>
|
|
90
|
+
</pre>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
},
|
|
94
|
+
args: {},
|
|
95
|
+
};
|