@axzydev/axzy_ui_system 1.3.6 → 1.4.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 +8 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/molecules/date-picker/datePicker.tsx +1 -0
- package/src/components/molecules/dropdown-menu/dropdown-menu.tsx +1 -0
- package/src/components/molecules/multi-select/multi-select.tsx +1 -0
- package/src/components/molecules/search-select/search-select.tsx +1 -0
- package/src/components/molecules/time-picker/timePicker.tsx +1 -0
- package/src/components/organisms/dialog/dialog.stories.tsx +48 -0
- package/src/hooks/useClickOutside.ts +6 -0
- package/src/hooks/useFloatingPanel.ts +4 -1
- package/src/showcases/FeedbackShowcases.tsx +16 -1
- package/src/showcases/HomeShowcase.tsx +552 -331
- package/src/showcases/ProductoDetalle.tsx +181 -0
- package/src/showcases/ProductoIcono.tsx +25 -0
- package/src/showcases/productos.ts +179 -0
- package/src/showcases/techIcons.ts +67 -0
package/package.json
CHANGED
|
@@ -283,6 +283,7 @@ export default function ITSearchSelect({
|
|
|
283
283
|
createPortal(
|
|
284
284
|
<div
|
|
285
285
|
ref={panelRef}
|
|
286
|
+
data-it-floating="true"
|
|
286
287
|
style={panelStyle}
|
|
287
288
|
className="bg-white dark:bg-slate-900 border border-secondary-200 dark:border-slate-800 rounded-lg shadow-xl overflow-hidden animate-in fade-in zoom-in duration-200 origin-top"
|
|
288
289
|
>
|
|
@@ -217,6 +217,7 @@ export default function ITTimePicker({
|
|
|
217
217
|
{isOpen && !disabled && createPortal(
|
|
218
218
|
<div
|
|
219
219
|
ref={dropdownRef}
|
|
220
|
+
data-it-floating="true"
|
|
220
221
|
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
222
|
style={panelStyle}
|
|
222
223
|
>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Meta } from '@storybook/react';
|
|
2
2
|
import ITDialog from '@/components/organisms/dialog/dialog';
|
|
3
|
+
import ITSearchSelect from '@/components/molecules/search-select/search-select';
|
|
3
4
|
import { useState } from 'react';
|
|
5
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
4
6
|
import ITButton from '@/components/atoms/button/button';
|
|
5
7
|
|
|
6
8
|
const meta = {
|
|
@@ -76,3 +78,49 @@ export const LongContent: any = {
|
|
|
76
78
|
className: 'w-[600px]',
|
|
77
79
|
} as any,
|
|
78
80
|
};
|
|
81
|
+
|
|
82
|
+
// Dialog opened on mount but controlled, so an unexpected close is observable.
|
|
83
|
+
const DialogWithSearchSelect = () => {
|
|
84
|
+
const [fruit, setFruit] = useState('');
|
|
85
|
+
const [isOpen, setIsOpen] = useState(true);
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<ITDialog isOpen={isOpen} onClose={() => setIsOpen(false)} title="Fruta favorita">
|
|
89
|
+
<ITSearchSelect
|
|
90
|
+
label="Fruta"
|
|
91
|
+
placeholder="Busca una fruta..."
|
|
92
|
+
options={[
|
|
93
|
+
{ value: 'apple', label: 'Apple' },
|
|
94
|
+
{ value: 'banana', label: 'Banana' },
|
|
95
|
+
]}
|
|
96
|
+
value={fruit}
|
|
97
|
+
onChange={(next) => setFruit(String(next))}
|
|
98
|
+
/>
|
|
99
|
+
</ITDialog>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Regression test: floating panels (selects, pickers, menus) are portaled to
|
|
105
|
+
* `<body>`, so they live outside the dialog DOM. Picking an option there must
|
|
106
|
+
* not count as a click outside the dialog.
|
|
107
|
+
*
|
|
108
|
+
* Note the whole dialog and its dropdown are portaled, so they are queried
|
|
109
|
+
* from `document.body` instead of the story canvas.
|
|
110
|
+
*/
|
|
111
|
+
export const FloatingPanelInsideDialog: any = {
|
|
112
|
+
render: () => <DialogWithSearchSelect />,
|
|
113
|
+
play: async () => {
|
|
114
|
+
const view = within(document.body);
|
|
115
|
+
|
|
116
|
+
const input = await view.findByPlaceholderText('Busca una fruta...');
|
|
117
|
+
await userEvent.click(input);
|
|
118
|
+
|
|
119
|
+
await userEvent.click(await view.findByText('Banana'));
|
|
120
|
+
|
|
121
|
+
// The dialog must still be mounted after picking an option.
|
|
122
|
+
await expect(view.getByText('Fruta favorita')).toBeVisible();
|
|
123
|
+
await expect((input as HTMLInputElement).value).toBe('Banana');
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
@@ -14,6 +14,12 @@ const useClickOutside = (
|
|
|
14
14
|
// child overlay or its contents.
|
|
15
15
|
if (clickedDialog && clickedDialog !== currentDialog) return;
|
|
16
16
|
|
|
17
|
+
// Floating panels (select/date/time pickers, menus) are portaled to
|
|
18
|
+
// <body>, so they sit outside the DOM of the dialog/drawer that opened
|
|
19
|
+
// them. Picking an option there must not count as an outside click.
|
|
20
|
+
const clickedFloating = target?.closest("[data-it-floating]");
|
|
21
|
+
if (clickedFloating && !ref.current?.contains(clickedFloating)) return;
|
|
22
|
+
|
|
17
23
|
if (ref.current && !ref.current.contains(event.target as Node)) {
|
|
18
24
|
callback();
|
|
19
25
|
}
|
|
@@ -57,7 +57,10 @@ export function useFloatingPanel(
|
|
|
57
57
|
const flipAbove = spaceBelow < panelHeight + offset && spaceAbove > spaceBelow;
|
|
58
58
|
|
|
59
59
|
const width = matchWidth ? rect.width : undefined;
|
|
60
|
-
|
|
60
|
+
// With matchWidth the final width is the anchor's. Measuring the panel
|
|
61
|
+
// here would read its pre-style width (a full-width block on first
|
|
62
|
+
// paint) and clamp `left` to the viewport edge until the next update.
|
|
63
|
+
const panelWidth = width ?? panelRef.current?.offsetWidth ?? 0;
|
|
61
64
|
let left =
|
|
62
65
|
align === "end" && panelWidth
|
|
63
66
|
? rect.right - panelWidth
|
|
@@ -2,6 +2,7 @@ import React, { useState } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
ITDialog,
|
|
4
4
|
ITButton,
|
|
5
|
+
ITSearchSelect,
|
|
5
6
|
ITSlideToggle,
|
|
6
7
|
ITToast,
|
|
7
8
|
ITInput,
|
|
@@ -18,8 +19,9 @@ import { ShowcaseLayout } from "./ShowcaseLayout";
|
|
|
18
19
|
export const DialogShowcase = () => {
|
|
19
20
|
const [isOpen, setIsOpen] = useState(false);
|
|
20
21
|
const [useFormHeader, setUseFormHeader] = useState(true);
|
|
22
|
+
const [auditor, setAuditor] = useState("");
|
|
21
23
|
|
|
22
|
-
const code = `<ITDialog\n isOpen={${isOpen}}\n onClose={() => setIsOpen(false)}\n title="Confirmación de Auditoría"\n useFormHeader={${useFormHeader}}\n>\n <p>¿Estás seguro de registrar esta auditoría?</p>\n</ITDialog>`;
|
|
24
|
+
const code = `<ITDialog\n isOpen={${isOpen}}\n onClose={() => setIsOpen(false)}\n title="Confirmación de Auditoría"\n useFormHeader={${useFormHeader}}\n>\n <p>¿Estás seguro de registrar esta auditoría?</p>\n <ITSearchSelect placeholder="Selecciona un auditor" ... />\n</ITDialog>`;
|
|
23
25
|
|
|
24
26
|
return (
|
|
25
27
|
<ShowcaseLayout
|
|
@@ -39,6 +41,19 @@ export const DialogShowcase = () => {
|
|
|
39
41
|
<p className="text-sm text-slate-600 dark:text-slate-300">
|
|
40
42
|
Se guardará un registro inmutable en los logs de la blockchain corporativa. Esta acción es irreversible.
|
|
41
43
|
</p>
|
|
44
|
+
{/* Los paneles flotantes (selects, pickers, menús) se renderizan en
|
|
45
|
+
un portal fuera del diálogo: elegir una opción no debe cerrarlo. */}
|
|
46
|
+
<ITSearchSelect
|
|
47
|
+
label="Auditor responsable"
|
|
48
|
+
placeholder="Busca un auditor..."
|
|
49
|
+
options={[
|
|
50
|
+
{ value: "ana", label: "Ana Torres" },
|
|
51
|
+
{ value: "luis", label: "Luis Paredes" },
|
|
52
|
+
{ value: "marta", label: "Marta Ruiz" },
|
|
53
|
+
]}
|
|
54
|
+
value={auditor}
|
|
55
|
+
onChange={(next) => setAuditor(String(next))}
|
|
56
|
+
/>
|
|
42
57
|
<div className="flex justify-end gap-3 pt-4 border-t">
|
|
43
58
|
<ITButton label="Cancelar" variant="ghost" onClick={() => setIsOpen(false)} />
|
|
44
59
|
<ITButton label="Autorizar" color="success" onClick={() => { alert("Transacción firmada!"); setIsOpen(false); }} />
|