Megacompact
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
Full Pure reactive JS UI +40 components in less than 35 KB!
|
||||
Full Pure reactive JS UI +40 components in less than 30 KB!
|
||||
|
||||
# SigPro UI
|
||||
|
||||
[](https://www.npmjs.com/package/sigpro)
|
||||

|
||||

|
||||

|
||||
[](https://github.com/natxocc/sigpro-ui/blob/main/LICENSE)
|
||||
|
||||
@@ -12,7 +12,7 @@ Full Pure reactive JS UI +40 components in less than 35 KB!
|
||||
Based in SigPro Core
|
||||
[**Explore the Core Docs →**](https://sigpro.natxocc.com/#/)
|
||||
|
||||
**SigPro UI** is a lightweight (<35KB JS+CSS), ultra-fast, and reactive component library built for the **SigPro** reactivity core. It provides a set of high-quality, accessible, and themeable UI components with **zero external dependencies**
|
||||
**SigPro UI** is a lightweight (<30KB JS+CSS), ultra-fast, and reactive component library built for the **SigPro** reactivity core. It provides a set of high-quality, accessible, and themeable UI components with **zero external dependencies**
|
||||
|
||||
Unlike heavy frameworks, SigPro UI focuses on a **"Zero-Build"** philosophy, allowing you to build complex reactive interfaces with a functional, declarative syntax that runs natively in the browser.
|
||||
|
||||
|
||||
575
dist/sigpro-ui.css
vendored
575
dist/sigpro-ui.css
vendored
@@ -1,4 +1,4 @@
|
||||
/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
|
||||
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
|
||||
@layer properties;
|
||||
@layer theme, base, components, utilities;
|
||||
@layer theme {
|
||||
@@ -11,7 +11,6 @@
|
||||
--spacing: 0.25rem;
|
||||
--container-xs: 20rem;
|
||||
--container-md: 28rem;
|
||||
--container-2xl: 42rem;
|
||||
--container-3xl: 48rem;
|
||||
--container-5xl: 64rem;
|
||||
--container-6xl: 72rem;
|
||||
@@ -35,7 +34,6 @@
|
||||
--text-9xl--line-height: 1;
|
||||
--font-weight-light: 300;
|
||||
--font-weight-normal: 400;
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-semibold: 600;
|
||||
--font-weight-bold: 700;
|
||||
--font-weight-black: 900;
|
||||
@@ -401,6 +399,57 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.drawer-open {
|
||||
@layer daisyui.l1.l2.l3 {
|
||||
> .drawer-toggle:checked {
|
||||
~ .drawer-side {
|
||||
scrollbar-color: revert-layer;
|
||||
}
|
||||
:root:has(&) {
|
||||
--page-overflow: revert-layer;
|
||||
--page-scroll-gutter: revert-layer;
|
||||
--page-scroll-bg: revert-layer;
|
||||
--page-scroll-transition: revert-layer;
|
||||
--page-has-backdrop: revert-layer;
|
||||
animation: revert-layer;
|
||||
animation-timeline: revert-layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer daisyui.l1.l2 {
|
||||
> .drawer-side {
|
||||
overflow-y: auto;
|
||||
}
|
||||
> .drawer-toggle {
|
||||
display: none;
|
||||
~ .drawer-side {
|
||||
pointer-events: auto;
|
||||
visibility: visible;
|
||||
position: sticky;
|
||||
display: block;
|
||||
width: auto;
|
||||
overscroll-behavior: auto;
|
||||
opacity: 100%;
|
||||
> .drawer-overlay {
|
||||
cursor: default;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
&:checked ~ .drawer-side {
|
||||
pointer-events: auto;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer daisyui.l1 {
|
||||
> .drawer-toggle ~ .drawer-side > :not(.drawer-overlay) {
|
||||
translate: 0%;
|
||||
[dir="rtl"] & {
|
||||
translate: 0%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.drawer-toggle {
|
||||
@layer daisyui.l1.l2.l3 {
|
||||
position: fixed;
|
||||
@@ -1328,9 +1377,6 @@
|
||||
.collapse {
|
||||
visibility: collapse;
|
||||
}
|
||||
.visible {
|
||||
visibility: visible;
|
||||
}
|
||||
.tabs-lift {
|
||||
@layer daisyui.l1.l2 {
|
||||
--tabs-height: auto;
|
||||
@@ -2823,9 +2869,6 @@
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
.sticky {
|
||||
position: sticky;
|
||||
}
|
||||
.tooltip-bottom {
|
||||
@layer daisyui.l1.l2 {
|
||||
> .tooltip-content, &[data-tip]:before {
|
||||
@@ -2938,9 +2981,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.start {
|
||||
inset-inline-start: var(--spacing);
|
||||
}
|
||||
.dropdown-left {
|
||||
@layer daisyui.l1.l2 {
|
||||
--anchor-h: left;
|
||||
@@ -2981,9 +3021,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.end {
|
||||
inset-inline-end: var(--spacing);
|
||||
}
|
||||
.dropdown-bottom {
|
||||
@layer daisyui.l1.l2 {
|
||||
--anchor-v: bottom;
|
||||
@@ -3007,24 +3044,24 @@
|
||||
.top-0 {
|
||||
top: calc(var(--spacing) * 0);
|
||||
}
|
||||
.top-2 {
|
||||
top: calc(var(--spacing) * 2);
|
||||
}
|
||||
.top-10 {
|
||||
top: calc(var(--spacing) * 10);
|
||||
}
|
||||
.top-full {
|
||||
top: 100%;
|
||||
}
|
||||
.right-0 {
|
||||
right: calc(var(--spacing) * 0);
|
||||
}
|
||||
.right-1\/4 {
|
||||
right: calc(1 / 4 * 100%);
|
||||
}
|
||||
.right-2 {
|
||||
right: calc(var(--spacing) * 2);
|
||||
}
|
||||
.bottom-10 {
|
||||
bottom: calc(var(--spacing) * 10);
|
||||
}
|
||||
.left-0 {
|
||||
left: calc(var(--spacing) * 0);
|
||||
}
|
||||
.left-1\/2 {
|
||||
left: calc(1 / 2 * 100%);
|
||||
}
|
||||
@@ -3101,6 +3138,116 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.file-input {
|
||||
@layer daisyui.l1.l2.l3 {
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
border: var(--border) solid #0000;
|
||||
display: inline-flex;
|
||||
appearance: none;
|
||||
align-items: center;
|
||||
background-color: var(--color-base-100);
|
||||
vertical-align: middle;
|
||||
webkit-user-select: none;
|
||||
user-select: none;
|
||||
width: clamp(3rem, 20rem, 100%);
|
||||
height: var(--size);
|
||||
padding-inline-end: 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 2;
|
||||
border-start-start-radius: var(--join-ss, var(--radius-field));
|
||||
border-start-end-radius: var(--join-se, var(--radius-field));
|
||||
border-end-start-radius: var(--join-es, var(--radius-field));
|
||||
border-end-end-radius: var(--join-ee, var(--radius-field));
|
||||
border-color: var(--input-color);
|
||||
box-shadow: 0 1px var(--input-color) inset, 0 -1px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset;
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
box-shadow: 0 1px color-mix(in oklab, var(--input-color) calc(var(--depth) * 10%), #0000) inset, 0 -1px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset;
|
||||
}
|
||||
--size: calc(var(--size-field, 0.25rem) * 10);
|
||||
--input-color: var(--color-base-content);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
--input-color: color-mix(in oklab, var(--color-base-content) 20%, #0000);
|
||||
}
|
||||
&::file-selector-button {
|
||||
margin-inline-end: calc(0.25rem * 4);
|
||||
cursor: pointer;
|
||||
padding-inline: calc(0.25rem * 4);
|
||||
webkit-user-select: none;
|
||||
user-select: none;
|
||||
height: calc(100% + var(--border) * 2);
|
||||
margin-block: calc(var(--border) * -1);
|
||||
margin-inline-start: calc(var(--border) * -1);
|
||||
font-size: 0.875rem;
|
||||
color: var(--btn-fg);
|
||||
border-width: var(--border);
|
||||
border-style: solid;
|
||||
border-color: var(--btn-border);
|
||||
border-start-start-radius: calc(var(--join-ss, var(--radius-field) - var(--border)));
|
||||
border-end-start-radius: calc(var(--join-es, var(--radius-field) - var(--border)));
|
||||
font-weight: 600;
|
||||
background-color: var(--btn-bg);
|
||||
background-size: calc(var(--noise) * 100%);
|
||||
background-image: var(--btn-noise);
|
||||
text-shadow: 0 0.5px oklch(1 0 0 / calc(var(--depth) * 0.15));
|
||||
box-shadow: 0 0.5px 0 0.5px white inset, var(--btn-shadow);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
box-shadow: 0 0.5px 0 0.5px color-mix( in oklab, color-mix(in oklab, white 30%, var(--btn-bg)) calc(var(--depth) * 20%), #0000 ) inset, var(--btn-shadow);
|
||||
}
|
||||
--size: calc(var(--size-field, 0.25rem) * 10);
|
||||
--btn-bg: var(--btn-color, var(--color-base-200));
|
||||
--btn-fg: var(--color-base-content);
|
||||
--btn-border: var(--btn-bg);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
--btn-border: color-mix(in oklab, var(--btn-bg), #000 5%);
|
||||
}
|
||||
--btn-shadow: 0 3px 2px -2px var(--btn-bg),
|
||||
0 4px 3px -2px var(--btn-bg);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
--btn-shadow: 0 3px 2px -2px color-mix(in oklab, var(--btn-bg) 30%, #0000),
|
||||
0 4px 3px -2px color-mix(in oklab, var(--btn-bg) 30%, #0000);
|
||||
}
|
||||
--btn-noise: var(--fx-noise);
|
||||
}
|
||||
&:focus {
|
||||
--input-color: var(--color-base-content);
|
||||
box-shadow: 0 1px var(--input-color);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
box-shadow: 0 1px color-mix(in oklab, var(--input-color) 10%, #0000);
|
||||
}
|
||||
outline: 2px solid var(--input-color);
|
||||
outline-offset: 2px;
|
||||
isolation: isolate;
|
||||
}
|
||||
&:has(> input[disabled]), &:is(:disabled, [disabled]) {
|
||||
cursor: not-allowed;
|
||||
border-color: var(--color-base-200);
|
||||
background-color: var(--color-base-200);
|
||||
&::placeholder {
|
||||
color: var(--color-base-content);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
color: color-mix(in oklab, var(--color-base-content) 20%, transparent);
|
||||
}
|
||||
}
|
||||
box-shadow: none;
|
||||
color: var(--color-base-content);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
color: color-mix(in oklch, var(--color-base-content) 20%, #0000);
|
||||
}
|
||||
&::file-selector-button {
|
||||
cursor: not-allowed;
|
||||
border-color: var(--color-base-200);
|
||||
background-color: var(--color-base-200);
|
||||
--btn-border: #0000;
|
||||
--btn-noise: none;
|
||||
--btn-fg: var(--color-base-content);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
--btn-fg: color-mix(in oklch, var(--color-base-content) 20%, #0000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.textarea {
|
||||
@layer daisyui.l1.l2.l3 {
|
||||
border: var(--border) solid #0000;
|
||||
@@ -3321,9 +3468,6 @@
|
||||
.z-10 {
|
||||
z-index: 10;
|
||||
}
|
||||
.z-20 {
|
||||
z-index: 20;
|
||||
}
|
||||
.z-50 {
|
||||
z-index: 50;
|
||||
}
|
||||
@@ -3777,9 +3921,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.mx-1 {
|
||||
margin-inline: calc(var(--spacing) * 1);
|
||||
}
|
||||
.mx-auto {
|
||||
margin-inline: auto;
|
||||
}
|
||||
@@ -4058,9 +4199,6 @@
|
||||
.mb-10 {
|
||||
margin-bottom: calc(var(--spacing) * 10);
|
||||
}
|
||||
.ml-1 {
|
||||
margin-left: calc(var(--spacing) * 1);
|
||||
}
|
||||
.ml-2 {
|
||||
margin-left: calc(var(--spacing) * 2);
|
||||
}
|
||||
@@ -4120,45 +4258,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m21.73 18l-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3M12 9v4m0 4h.01'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--align-center\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M17 12H7m12 6H5M21 6H3'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--align-left\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M15 12H3m14 6H3M21 6H3'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--align-right\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 12H9m12 6H7M21 6H3'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--bell\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4289,19 +4388,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 6v6l4 2'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--code-2\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m18 16l4-4l-4-4M6 8l-4 4l4 4m8.5-12l-5 16'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--eye-off\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4367,32 +4453,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8'/%3E%3Cpath d='M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--indent-decrease\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 12H11m10 6H11M21 6H11M7 8l-4 4l4 4'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--indent-increase\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 12H11m10 6H11M21 6H11M3 8l4 4l-4 4'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--info\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4406,19 +4466,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 16v-4m0-4h.01'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--italic\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 4h-9m4 16H5M15 4L9 20'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--link\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4432,32 +4479,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71'/%3E%3Cpath d='M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--list-ordered\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M11 5h10m-10 7h10m-10 7h10M4 4h1v5M4 9h2m.5 11H3.4c0-1 2.6-1.925 2.6-3.5a1.5 1.5 0 0 0-2.6-1.02'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--list\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M3 5h.01M3 12h.01M3 19h.01M8 5h13M8 12h13M8 19h13'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--lock\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4510,19 +4531,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--paperclip\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m16 6l-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--phone\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4536,32 +4544,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233a14 14 0 0 0 6.392 6.384'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--quote\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2a1 1 0 0 1 1 1v1a2 2 0 0 1-2 2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1a6 6 0 0 0 6-6V5a2 2 0 0 0-2-2zM5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2a1 1 0 0 1 1 1v1a2 2 0 0 1-2 2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1a6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--redo-2\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='m15 14l5-5l-5-5'/%3E%3Cpath d='M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--search\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4588,19 +4570,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M9.671 4.136a2.34 2.34 0 0 1 4.659 0a2.34 2.34 0 0 0 3.319 1.915a2.34 2.34 0 0 1 2.33 4.033a2.34 2.34 0 0 0 0 3.831a2.34 2.34 0 0 1-2.33 4.033a2.34 2.34 0 0 0-3.319 1.915a2.34 2.34 0 0 1-4.659 0a2.34 2.34 0 0 0-3.32-1.915a2.34 2.34 0 0 1-2.33-4.033a2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--smile\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M8 14s1.5 2 4 2s4-2 4-2M9 9h.01M15 9h.01'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--sun\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4627,32 +4596,6 @@
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M15 18H3M17 6H3m18 6H3'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--underline\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 4v6a6 6 0 0 0 12 0V4M4 20h16'/%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--undo-2\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: var(--svg);
|
||||
mask-image: var(--svg);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M9 14L4 9l5-5'/%3E%3Cpath d='M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11'/%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.icon-\[lucide--upload\] {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
@@ -4939,12 +4882,6 @@
|
||||
mask-position: center;
|
||||
}
|
||||
}
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
.contents {
|
||||
display: contents;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
@@ -5061,15 +4998,9 @@
|
||||
width: calc(var(--spacing) * 6);
|
||||
height: calc(var(--spacing) * 6);
|
||||
}
|
||||
.h-3 {
|
||||
height: calc(var(--spacing) * 3);
|
||||
}
|
||||
.h-4 {
|
||||
height: calc(var(--spacing) * 4);
|
||||
}
|
||||
.h-5 {
|
||||
height: calc(var(--spacing) * 5);
|
||||
}
|
||||
.h-12 {
|
||||
height: calc(var(--spacing) * 12);
|
||||
}
|
||||
@@ -5097,9 +5028,6 @@
|
||||
.min-h-0 {
|
||||
min-height: calc(var(--spacing) * 0);
|
||||
}
|
||||
.min-h-\[22rem\] {
|
||||
min-height: 22rem;
|
||||
}
|
||||
.min-h-full {
|
||||
min-height: 100%;
|
||||
}
|
||||
@@ -5138,18 +5066,9 @@
|
||||
width: calc(var(--size-selector, 0.25rem) * 7);
|
||||
}
|
||||
}
|
||||
.w-3 {
|
||||
width: calc(var(--spacing) * 3);
|
||||
}
|
||||
.w-3\/4 {
|
||||
width: calc(3 / 4 * 100%);
|
||||
}
|
||||
.w-4 {
|
||||
width: calc(var(--spacing) * 4);
|
||||
}
|
||||
.w-5 {
|
||||
width: calc(var(--spacing) * 5);
|
||||
}
|
||||
.w-10 {
|
||||
width: calc(var(--spacing) * 10);
|
||||
}
|
||||
@@ -5189,15 +5108,9 @@
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
.w-px {
|
||||
width: 1px;
|
||||
}
|
||||
.w-xs {
|
||||
width: var(--container-xs);
|
||||
}
|
||||
.max-w-2xl {
|
||||
max-width: var(--container-2xl);
|
||||
}
|
||||
.max-w-3xl {
|
||||
max-width: var(--container-3xl);
|
||||
}
|
||||
@@ -5207,24 +5120,18 @@
|
||||
.max-w-6xl {
|
||||
max-width: var(--container-6xl);
|
||||
}
|
||||
.max-w-\[200px\] {
|
||||
max-width: 200px;
|
||||
.max-w-\[180px\] {
|
||||
max-width: 180px;
|
||||
}
|
||||
.max-w-md {
|
||||
max-width: var(--container-md);
|
||||
}
|
||||
.min-w-\[48px\] {
|
||||
min-width: 48px;
|
||||
}
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
.flex-none {
|
||||
flex: none;
|
||||
}
|
||||
.shrink-0 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
@@ -5352,9 +5259,6 @@
|
||||
.justify-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.gap-0\.5 {
|
||||
gap: calc(var(--spacing) * 0.5);
|
||||
}
|
||||
.gap-1 {
|
||||
gap: calc(var(--spacing) * 1);
|
||||
}
|
||||
@@ -5380,6 +5284,13 @@
|
||||
margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)));
|
||||
}
|
||||
}
|
||||
.space-y-2 {
|
||||
:where(& > :not(:last-child)) {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));
|
||||
margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)));
|
||||
}
|
||||
}
|
||||
.space-y-4 {
|
||||
:where(& > :not(:last-child)) {
|
||||
--tw-space-y-reverse: 0;
|
||||
@@ -5448,10 +5359,6 @@
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 1px;
|
||||
}
|
||||
.border-0 {
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 0px;
|
||||
}
|
||||
.border-2 {
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 2px;
|
||||
@@ -5620,12 +5527,6 @@
|
||||
.bg-base-100 {
|
||||
background-color: var(--color-base-100);
|
||||
}
|
||||
.bg-base-100\/50 {
|
||||
background-color: var(--color-base-100);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
background-color: color-mix(in oklab, var(--color-base-100) 50%, transparent);
|
||||
}
|
||||
}
|
||||
.bg-base-200 {
|
||||
background-color: var(--color-base-200);
|
||||
}
|
||||
@@ -5662,9 +5563,6 @@
|
||||
.bg-secondary {
|
||||
background-color: var(--color-secondary);
|
||||
}
|
||||
.bg-transparent {
|
||||
background-color: transparent;
|
||||
}
|
||||
.bg-linear-to-r {
|
||||
--tw-gradient-position: to right;
|
||||
@supports (background-image: linear-gradient(in lab, red, red)) {
|
||||
@@ -5829,6 +5727,18 @@
|
||||
.p-10 {
|
||||
padding: calc(var(--spacing) * 10);
|
||||
}
|
||||
.menu-title {
|
||||
@layer daisyui.l1.l2.l3 {
|
||||
padding-inline: calc(0.25rem * 3);
|
||||
padding-block: calc(0.25rem * 2);
|
||||
color: var(--color-base-content);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
color: color-mix(in oklab, var(--color-base-content) 40%, transparent);
|
||||
}
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.select-lg {
|
||||
@layer daisyui.l1.l2 {
|
||||
--size: calc(var(--size-field, 0.25rem) * 12);
|
||||
@@ -5916,9 +5826,6 @@
|
||||
.px-1 {
|
||||
padding-inline: calc(var(--spacing) * 1);
|
||||
}
|
||||
.px-3 {
|
||||
padding-inline: calc(var(--spacing) * 3);
|
||||
}
|
||||
.px-4 {
|
||||
padding-inline: calc(var(--spacing) * 4);
|
||||
}
|
||||
@@ -5928,8 +5835,8 @@
|
||||
.px-10 {
|
||||
padding-inline: calc(var(--spacing) * 10);
|
||||
}
|
||||
.py-1 {
|
||||
padding-block: calc(var(--spacing) * 1);
|
||||
.py-4 {
|
||||
padding-block: calc(var(--spacing) * 4);
|
||||
}
|
||||
.py-10 {
|
||||
padding-block: calc(var(--spacing) * 10);
|
||||
@@ -5955,9 +5862,6 @@
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
.font-mono {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
@@ -6065,10 +5969,6 @@
|
||||
--tw-font-weight: var(--font-weight-light);
|
||||
font-weight: var(--font-weight-light);
|
||||
}
|
||||
.font-medium {
|
||||
--tw-font-weight: var(--font-weight-medium);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
.font-normal {
|
||||
--tw-font-weight: var(--font-weight-normal);
|
||||
font-weight: var(--font-weight-normal);
|
||||
@@ -6092,9 +5992,6 @@
|
||||
.text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
.whitespace-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.alert-error {
|
||||
@layer daisyui.l1.l2 {
|
||||
color: var(--color-error-content);
|
||||
@@ -6359,9 +6256,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
.swap-active {
|
||||
@layer daisyui.l1.l2 {
|
||||
.swap-off {
|
||||
@@ -6416,10 +6310,6 @@
|
||||
--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
.shadow-sm {
|
||||
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
.shadow-xl {
|
||||
--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
@@ -6491,10 +6381,6 @@
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
}
|
||||
.duration-200 {
|
||||
--tw-duration: 200ms;
|
||||
transition-duration: 200ms;
|
||||
}
|
||||
.duration-300 {
|
||||
--tw-duration: 300ms;
|
||||
transition-duration: 300ms;
|
||||
@@ -6692,10 +6578,6 @@
|
||||
--btn-fg: var(--color-warning-content);
|
||||
}
|
||||
}
|
||||
.outline-none {
|
||||
--tw-outline-style: none;
|
||||
outline-style: none;
|
||||
}
|
||||
.select-none {
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
@@ -6804,9 +6686,6 @@
|
||||
--range-thumb-size: calc(var(--size-selector, 0.25rem) * 4);
|
||||
}
|
||||
}
|
||||
.ring-inset {
|
||||
--tw-ring-inset: inset;
|
||||
}
|
||||
.select-accent {
|
||||
@layer daisyui.l1.l2 {
|
||||
&, &:focus, &:focus-within {
|
||||
@@ -6970,13 +6849,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.hover\:bg-base-200 {
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
background-color: var(--color-base-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
.hover\:bg-base-300 {
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
@@ -7094,71 +6966,6 @@
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
.\[\&_\.resizable-img-container\]\:hover\:border-primary {
|
||||
& .resizable-img-container {
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.\[\&_blockquote\]\:border-l-4 {
|
||||
& blockquote {
|
||||
border-left-style: var(--tw-border-style);
|
||||
border-left-width: 4px;
|
||||
}
|
||||
}
|
||||
.\[\&_blockquote\]\:border-base-300 {
|
||||
& blockquote {
|
||||
border-color: var(--color-base-300);
|
||||
}
|
||||
}
|
||||
.\[\&_blockquote\]\:pl-4 {
|
||||
& blockquote {
|
||||
padding-left: calc(var(--spacing) * 4);
|
||||
}
|
||||
}
|
||||
.\[\&_blockquote\]\:italic {
|
||||
& blockquote {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
.\[\&_ol\]\:list-decimal {
|
||||
& ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
}
|
||||
.\[\&_ol\]\:pl-8 {
|
||||
& ol {
|
||||
padding-left: calc(var(--spacing) * 8);
|
||||
}
|
||||
}
|
||||
.\[\&_ul\]\:list-disc {
|
||||
& ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
}
|
||||
.\[\&_ul\]\:pl-8 {
|
||||
& ul {
|
||||
padding-left: calc(var(--spacing) * 8);
|
||||
}
|
||||
}
|
||||
.\[\&\>div\]\:m-0 {
|
||||
&>div {
|
||||
margin: calc(var(--spacing) * 0);
|
||||
}
|
||||
}
|
||||
.\[\&\>div\]\:min-h-\[1em\] {
|
||||
&>div {
|
||||
min-height: 1em;
|
||||
}
|
||||
}
|
||||
.\[\&\>p\]\:m-0 {
|
||||
&>p {
|
||||
margin: calc(var(--spacing) * 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
:root {
|
||||
font-size: 14px;
|
||||
|
||||
295
dist/sigpro-ui.editor.esm.js
vendored
295
dist/sigpro-ui.editor.esm.js
vendored
@@ -1,295 +0,0 @@
|
||||
// src/editor.js
|
||||
import { $ as $2, isFunc as isFunc2, h as h2 } from "sigpro";
|
||||
|
||||
// src/sigpro-ui.js
|
||||
import { $, watch, h, mount, when, each, isFunc } from "sigpro";
|
||||
var val = (val2) => typeof val2 === "function" ? val2() : val2;
|
||||
var cls = (...classes) => classes.filter(Boolean).join(" ").trim();
|
||||
var c1 = (tag, cls2) => (p) => h(tag, { ...p, class: `${cls2} ${p?.class || ""}`.trim() });
|
||||
var c2 = (tag, cls2) => (p, c) => h(tag, { ...p, class: `${cls2} ${p?.class || ""}`.trim() }, c);
|
||||
var ct = (tag, cls2, type) => (p) => h(tag, { type, ...p, class: `${cls2} ${p?.class || ""}`.trim() });
|
||||
var Alert = c2("div", "alert");
|
||||
var AvatarGroup = c2("div", "avatar-group -space-x-6");
|
||||
var Badge = c2("span", "badge");
|
||||
var Breadcrumbs = c2("div", "breadcrumbs");
|
||||
var Button = c2("button", "btn");
|
||||
var Card = c2("div", "card");
|
||||
var CardTitle = c2("div", "card-title");
|
||||
var CardBody = c2("div", "card-body");
|
||||
var CardActions = c2("div", "card-actions");
|
||||
var Carousel = c2("div", "carousel");
|
||||
var CarouselItem = c2("div", "carousel-item");
|
||||
var Chat = c2("div", "chat");
|
||||
var ChatBubble = c2("div", "chat-bubble");
|
||||
var ChatFooter = c2("div", "chat-footer");
|
||||
var ChatHeader = c2("div", "chat-header");
|
||||
var Checkbox = ct("input", "checkbox", "checkbox");
|
||||
var Drawer = c2("div", "drawer");
|
||||
var DrawerContent = c2("div", "drawer-content");
|
||||
var DrawerSide = c2("div", "drawer-side");
|
||||
var Divider = c1("div", "divider");
|
||||
var Dropdown = c2("div", "dropdown");
|
||||
var Kbd = c2("kbd", "kbd");
|
||||
var List = c2("ul", "list");
|
||||
var Loading = c2("span", "loading loading-spinner");
|
||||
var Navbar = c2("div", "navbar");
|
||||
var Progress = c1("progress", "progress");
|
||||
var Radio = ct("input", "radio", "radio");
|
||||
var Range = ct("input", "range", "range");
|
||||
var Rating = c2("div", "rating");
|
||||
var Skeleton = c1("div", "skeleton");
|
||||
var SkeletonText = c1("span", "skeleton skeleton-text");
|
||||
var Stack = c2("div", "stack");
|
||||
var Stats = c2("div", "stats shadow");
|
||||
var Steps = c2("ul", "steps");
|
||||
var Swap = c2("label", "swap");
|
||||
var SwapOn = c2("div", "swap-on");
|
||||
var SwapOff = c2("div", "swap-off");
|
||||
var Table = c2("table", "table");
|
||||
var Textarea = c1("textarea", "textarea");
|
||||
var Timeline = c2("ul", "timeline");
|
||||
var Toggle = ct("input", "toggle", "checkbox");
|
||||
|
||||
// src/editor.js
|
||||
var Editor = (p) => {
|
||||
const { value, class: extraClass } = p;
|
||||
let editorRef = null;
|
||||
let savedRange = null;
|
||||
const isSource = $2(false);
|
||||
const source = $2("");
|
||||
const count = $2(0);
|
||||
const refreshTick = $2(0);
|
||||
const showEmojis = $2(false);
|
||||
const emojis = ["\uD83D\uDE00", "\uD83D\uDE0A", "\uD83D\uDE09", "\uD83E\uDDD0", "\uD83D\uDE2E", "\uD83E\uDD14", "\uD83D\uDE05", "\uD83D\uDE02", "\uD83D\uDE0D", "\uD83D\uDE18", "\uD83E\uDD70", "\uD83D\uDC4D", "\uD83D\uDC4E", "\uD83D\uDC4C", "\uD83E\uDD1D", "\uD83E\uDD1E", "\uD83D\uDC4B", "\uD83D\uDC4F", "\uD83D\uDE4C", "\uD83D\uDE4F", "\uD83D\uDCAA", "☝️", "\uD83D\uDC47", "\uD83D\uDC48", "\uD83D\uDC49", "\uD83D\uDD95", "✅", "⚠️", "\uD83D\uDE80", "\uD83D\uDCE2", "✉️", "❤️"];
|
||||
const saveSelection = () => {
|
||||
const sel = window.getSelection();
|
||||
if (sel.getRangeAt && sel.rangeCount)
|
||||
savedRange = sel.getRangeAt(0);
|
||||
};
|
||||
const restoreSelection = () => {
|
||||
if (savedRange) {
|
||||
const sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(savedRange);
|
||||
}
|
||||
};
|
||||
const triggerRefresh = () => {
|
||||
refreshTick(refreshTick() + 1);
|
||||
if (editorRef)
|
||||
count(editorRef.innerText.length);
|
||||
};
|
||||
const notify = () => {
|
||||
if (!editorRef)
|
||||
return;
|
||||
const html = editorRef.innerHTML;
|
||||
if (isFunc2(value))
|
||||
value(html);
|
||||
else
|
||||
p.onchange?.(html);
|
||||
triggerRefresh();
|
||||
};
|
||||
const exec = (cmd, val2 = null) => {
|
||||
if (!editorRef)
|
||||
return;
|
||||
editorRef.focus();
|
||||
if (savedRange)
|
||||
restoreSelection();
|
||||
document.execCommand(cmd, false, val2);
|
||||
savedRange = null;
|
||||
notify();
|
||||
};
|
||||
const openLightbox = (src) => {
|
||||
const overlay = document.createElement("div");
|
||||
overlay.style = `position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);z-index:9999;display:flex;align-items:center;justify-content:center;cursor:zoom-out;`;
|
||||
const img = document.createElement("img");
|
||||
img.src = src;
|
||||
img.style = `max-width:95%;max-height:95%;box-shadow:0 0 30px rgba(0,0,0,0.5);border-radius:4px;`;
|
||||
overlay.onclick = () => document.body.removeChild(overlay);
|
||||
overlay.appendChild(img);
|
||||
document.body.appendChild(overlay);
|
||||
};
|
||||
const handleUpload = (file) => {
|
||||
if (!file)
|
||||
return;
|
||||
const reader = new FileReader;
|
||||
reader.onload = (re) => {
|
||||
if (file.type.startsWith("image/")) {
|
||||
const imgHtml = `<div style="display:inline-block; resize:both; overflow:hidden; vertical-align:bottom; line-height:0; width:200px; height:auto; border:1px dashed #ccc; padding:2px; cursor:pointer;" class="resizable-img-container"><img src="${re.target.result}" style="width:100%; height:100%; object-fit:contain; pointer-events:none;"></div> `;
|
||||
exec("insertHTML", imgHtml);
|
||||
} else {
|
||||
const linkHtml = `<a href="${re.target.result}" download="${file.name}" contenteditable="false" style="display:inline-flex; align-items:center; gap:5px; padding:4px 8px; border:1px solid #ccc; border-radius:4px; background:#f9f9f9; text-decoration:none; color:#333; font-size:12px; margin:2px; cursor:pointer;"><span class="icon-[lucide--paperclip] w-3 h-3"></span>${file.name}</a> `;
|
||||
exec("insertHTML", linkHtml);
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
const queryState = (cmd, val2 = null) => {
|
||||
refreshTick();
|
||||
if (!editorRef || isSource())
|
||||
return false;
|
||||
try {
|
||||
if (cmd === "formatBlock") {
|
||||
let node = window.getSelection().getRangeAt(0).commonAncestorContainer;
|
||||
while (node && node !== editorRef) {
|
||||
if (node.nodeType === 1 && node.tagName === val2)
|
||||
return true;
|
||||
node = node.parentNode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return document.queryCommandState(cmd);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const toolbar = h2("div", { class: "flex flex-wrap items-center gap-1 p-2 border-b border-base-300 bg-base-200 sticky top-0 z-20" }, [
|
||||
h2("div", { class: "flex flex-wrap gap-1 flex-1 items-center" }, [
|
||||
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("bold") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("bold") }, h2("span", { class: "icon-[lucide--bold]" })),
|
||||
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("italic") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("italic") }, h2("span", { class: "icon-[lucide--italic]" })),
|
||||
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("underline") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("underline") }, h2("span", { class: "icon-[lucide--underline]" })),
|
||||
h2("input", { type: "color", class: "w-5 h-5 p-0 border-0 bg-transparent cursor-pointer", oninput: (e) => exec("foreColor", e.target.value) }),
|
||||
h2("span", { class: "w-px h-5 bg-base-300 mx-1" }),
|
||||
h2("button", {
|
||||
type: "button",
|
||||
class: "btn btn-ghost btn-xs",
|
||||
onclick: () => exec("justifyLeft")
|
||||
}, h2("span", { class: "icon-[lucide--align-left]" })),
|
||||
h2("button", {
|
||||
type: "button",
|
||||
class: "btn btn-ghost btn-xs",
|
||||
onclick: () => exec("justifyCenter")
|
||||
}, h2("span", { class: "icon-[lucide--align-center]" })),
|
||||
h2("button", {
|
||||
type: "button",
|
||||
class: "btn btn-ghost btn-xs",
|
||||
onclick: () => exec("justifyRight")
|
||||
}, h2("span", { class: "icon-[lucide--align-right]" })),
|
||||
h2("span", { class: "w-px h-5 bg-base-300 mx-1" }),
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("insertUnorderedList") }, h2("span", { class: "icon-[lucide--list]" })),
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("insertOrderedList") }, h2("span", { class: "icon-[lucide--list-ordered]" })),
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("outdent") }, h2("span", { class: "icon-[lucide--indent-decrease]" })),
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("indent") }, h2("span", { class: "icon-[lucide--indent-increase]" })),
|
||||
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("formatBlock", "BLOCKQUOTE") ? "btn-active" : ""}`, onclick: () => exec("formatBlock", queryState("formatBlock", "BLOCKQUOTE") ? "P" : "BLOCKQUOTE") }, h2("span", { class: "icon-[lucide--quote]" })),
|
||||
h2("span", { class: "w-px h-5 bg-base-300 mx-1" }),
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => {
|
||||
const url = window.prompt("URL:");
|
||||
if (url)
|
||||
exec("createLink", url);
|
||||
} }, h2("span", { class: "icon-[lucide--link]" })),
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => {
|
||||
const input2 = document.createElement("input");
|
||||
input2.type = "file";
|
||||
input2.onchange = (e) => handleUpload(e.target.files[0]);
|
||||
input2.click();
|
||||
} }, h2("span", { class: "icon-[lucide--paperclip]" })),
|
||||
h2("div", { class: "relative" }, [
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: (e) => {
|
||||
e.stopPropagation();
|
||||
saveSelection();
|
||||
showEmojis(!showEmojis());
|
||||
} }, h2("span", { class: "icon-[lucide--smile]" })),
|
||||
h2("div", { class: "absolute top-full left-0 mt-1 p-2 bg-base-100 border border-base-300 shadow-xl rounded-box w-52 z-50 flex flex-wrap gap-1", style: () => showEmojis() ? "display:flex" : "display:none" }, emojis.map((emo) => h2("span", { class: "cursor-pointer hover:bg-base-200 p-1 rounded text-lg", onclick: (e) => {
|
||||
e.stopPropagation();
|
||||
exec("insertText", emo);
|
||||
showEmojis(false);
|
||||
} }, emo)))
|
||||
]),
|
||||
h2("span", { class: "w-px h-5 bg-base-300 mx-1" }),
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("undo") }, h2("span", { class: "icon-[lucide--undo-2]" })),
|
||||
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("redo") }, h2("span", { class: "icon-[lucide--redo-2]" }))
|
||||
]),
|
||||
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${isSource() ? "btn-active" : ""}`, onclick: () => {
|
||||
if (!isSource())
|
||||
source(editorRef?.innerHTML || "");
|
||||
else if (editorRef) {
|
||||
editorRef.innerHTML = source();
|
||||
notify();
|
||||
}
|
||||
isSource(!isSource());
|
||||
} }, h2("span", { class: "icon-[lucide--code-2]" }))
|
||||
]);
|
||||
if (typeof document !== "undefined" && !document.getElementById("editor-styles")) {
|
||||
const style = document.createElement("style");
|
||||
style.id = "editor-styles";
|
||||
style.textContent = `
|
||||
[contenteditable="true"] div,
|
||||
[contenteditable="true"] p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
return h2("div", { class: cls("border border-base-300 rounded-box bg-base-100 overflow-hidden shadow-sm flex flex-col", extraClass) }, [
|
||||
toolbar,
|
||||
h2("div", { class: "relative flex-1 flex flex-col", onclick: () => showEmojis(false) }, [
|
||||
h2("div", {
|
||||
ref: (el) => {
|
||||
if (!editorRef && el) {
|
||||
editorRef = el;
|
||||
el.innerHTML = val(value) || "";
|
||||
document.execCommand("defaultParagraphSeparator", false, "br");
|
||||
el.addEventListener("click", (e) => {
|
||||
const container = e.target.closest(".resizable-img-container");
|
||||
if (container) {
|
||||
const img = container.querySelector("img");
|
||||
if (img)
|
||||
openLightbox(img.src);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
style: () => `min-height:22rem;${isSource() ? "display:none" : ""}`,
|
||||
class: "p-4 outline-none text-base-content leading-relaxed [&>div]:m-0 [&>p]:m-0 [&>div]:min-h-[1em] [&_.resizable-img-container]:hover:border-primary [&_blockquote]:border-l-4 [&_blockquote]:border-base-300 [&_blockquote]:pl-4 [&_blockquote]:italic [&_ul]:list-disc [&_ul]:pl-8 [&_ol]:list-decimal [&_ol]:pl-8",
|
||||
contenteditable: "true",
|
||||
oninput: notify,
|
||||
onkeydown: (e) => {
|
||||
if (e.key === "Tab") {
|
||||
e.preventDefault();
|
||||
exec("indent");
|
||||
}
|
||||
},
|
||||
onkeyup: () => {
|
||||
triggerRefresh();
|
||||
saveSelection();
|
||||
},
|
||||
onclick: (e) => {
|
||||
triggerRefresh();
|
||||
saveSelection();
|
||||
e.stopPropagation();
|
||||
},
|
||||
onmouseup: () => {
|
||||
notify();
|
||||
saveSelection();
|
||||
},
|
||||
onpaste: (e) => {
|
||||
e.preventDefault();
|
||||
const text = e.clipboardData.getData("text/plain");
|
||||
exec("insertText", text);
|
||||
},
|
||||
ondragover: (e) => e.preventDefault(),
|
||||
ondrop: (e) => {
|
||||
e.preventDefault();
|
||||
handleUpload(e.dataTransfer.files[0]);
|
||||
}
|
||||
}),
|
||||
h2("textarea", {
|
||||
class: "w-full flex-1 min-h-[22rem] p-4 outline-none font-mono text-sm bg-base-200 border-0",
|
||||
style: () => isSource() ? "" : "display:none",
|
||||
value: source,
|
||||
oninput: (e) => {
|
||||
source(e.target.value);
|
||||
if (editorRef)
|
||||
editorRef.innerHTML = e.target.value;
|
||||
p.onchange?.(e.target.value);
|
||||
}
|
||||
})
|
||||
]),
|
||||
h2("div", { class: "px-3 py-1 border-t border-base-300 bg-base-100/50 text-[10px] text-right text-base-content/60 italic" }, [
|
||||
h2("span", () => `${count()}`)
|
||||
])
|
||||
]);
|
||||
};
|
||||
export {
|
||||
Editor
|
||||
};
|
||||
7
dist/sigpro-ui.editor.esm.min.js
vendored
7
dist/sigpro-ui.editor.esm.min.js
vendored
File diff suppressed because one or more lines are too long
819
dist/sigpro-ui.esm.js
vendored
819
dist/sigpro-ui.esm.js
vendored
@@ -1,633 +1,220 @@
|
||||
// src/sigpro-ui.js
|
||||
import { $, watch, h, mount, when, each, isFunc } from "sigpro";
|
||||
var val = (val2) => typeof val2 === "function" ? val2() : val2;
|
||||
import { $, h, mount, val, isFunc } from "sigpro";
|
||||
var getBy = (item, field = "label") => item && typeof item === "object" ? item[field] : item;
|
||||
var cls = (...classes) => classes.filter(Boolean).join(" ").trim();
|
||||
var filterBy = (items, query, field = "label") => {
|
||||
const q = String(val(query) || "").toLowerCase();
|
||||
const list = (val(items) || []).map((i) => typeof i === "object" ? i : { label: i, value: i });
|
||||
return !q ? list : list.filter((item) => String(item[field] || "").toLowerCase().includes(q));
|
||||
};
|
||||
var rand = (r) => `${r}-${Math.random().toString(36).slice(2, 9)}`;
|
||||
var hide = () => document.activeElement?.blur();
|
||||
var c1 = (tag, cls2) => (p) => h(tag, { ...p, class: `${cls2} ${p?.class || ""}`.trim() });
|
||||
var c2 = (tag, cls2) => (p, c) => h(tag, { ...p, class: `${cls2} ${p?.class || ""}`.trim() }, c);
|
||||
var ct = (tag, cls2, type) => (p) => h(tag, { type, ...p, class: `${cls2} ${p?.class || ""}`.trim() });
|
||||
var Alert = c2("div", "alert");
|
||||
var Accordion = (p, c) => h("div", { ...p, class: `${"collapse"} ${p?.class || ""}`.trim() }, c);
|
||||
var AccordionRadio = (p) => h("input", { type: "radio", name: p.name, checked: p.checked || undefined, class: p.class });
|
||||
var AccordionTitle = (p, c) => h("div", { ...p, class: `${"collapse-title"} ${p?.class || ""}`.trim() }, c);
|
||||
var AccordionContent = (p, c) => h("div", { ...p, class: `${"collapse-content"} ${p?.class || ""}`.trim() }, c);
|
||||
var Alert = (p, c) => h("div", { ...p, class: `${"alert"} ${p?.class || ""}`.trim() }, c);
|
||||
var Avatar = (p, c) => h("div", { class: "avatar" }, h("div", { class: p.class }, c));
|
||||
var AvatarGroup = c2("div", "avatar-group -space-x-6");
|
||||
var Badge = c2("span", "badge");
|
||||
var Breadcrumbs = c2("div", "breadcrumbs");
|
||||
var Button = c2("button", "btn");
|
||||
var Card = c2("div", "card");
|
||||
var CardTitle = c2("div", "card-title");
|
||||
var CardBody = c2("div", "card-body");
|
||||
var CardActions = c2("div", "card-actions");
|
||||
var Carousel = c2("div", "carousel");
|
||||
var CarouselItem = c2("div", "carousel-item");
|
||||
var Chat = c2("div", "chat");
|
||||
var ChatBubble = c2("div", "chat-bubble");
|
||||
var ChatFooter = c2("div", "chat-footer");
|
||||
var ChatHeader = c2("div", "chat-header");
|
||||
var ChatImage = (p, c) => h("div", { ...p, class: cls("chat-image avatar", p.class) }, h("div", { class: "w-10 rounded-full" }, typeof c === "string" ? h("img", { src: c, alt: "avatar" }) : c));
|
||||
var Checkbox = ct("input", "checkbox", "checkbox");
|
||||
var Drawer = c2("div", "drawer");
|
||||
var DrawerToggle = (p) => input({ ...p, type: "checkbox", class: "drawer-toggle", checked: () => val(p.checked), onchange: (e) => isFunc(p.checked) && p.checked(e.target.checked) });
|
||||
var DrawerContent = c2("div", "drawer-content");
|
||||
var DrawerSide = c2("div", "drawer-side");
|
||||
var DrawerOverlay = (p) => label({ ...p, for: p.for, class: cls("drawer-overlay", p.class) });
|
||||
var Divider = c1("div", "divider");
|
||||
var Dropdown = c2("div", "dropdown");
|
||||
var DropdownButton = (p, c) => h("div", { ...p, tabindex: "0", role: "button", class: cls("btn", p.class) }, c);
|
||||
var DropdownContent = (p, c) => h("div", { ...p, tabindex: "0", class: cls("dropdown-content", p.class) }, c);
|
||||
var Fab = (p, c) => h("div", { class: "fab" }, [h("div", { tabindex: "0", role: "button", class: cls("btn", p.class) }, Icon({}, p.icon)), c]);
|
||||
var Fieldset = (p, c) => h("fieldset", { class: cls("fieldset", p.class) }, [h("legend", { class: "fieldset-legend" }, p.label), c]);
|
||||
var Icon = (p, c) => h("span", { ...p, class: cls(c, p.class) });
|
||||
var Indicator = (p, c) => h("div", { ...p, class: cls("indicator", p.class) }, [p.value && h("span", { class: cls("indicator-item badge", p.class) }, p.value), c]);
|
||||
var Kbd = c2("kbd", "kbd");
|
||||
var List = c2("ul", "list");
|
||||
var ListRows = (p) => () => (val(p.items) || []).map((item, idx) => h("li", { class: cls("list-row", p.class, item?.class) }, typeof p.render === "function" ? p.render(item, idx) : item));
|
||||
var Loading = c2("span", "loading loading-spinner");
|
||||
var Navbar = c2("div", "navbar");
|
||||
var Progress = c1("progress", "progress");
|
||||
var Radial = (p, c) => h("div", { class: cls("radial-progress", p.class), style: `--value:${val(p.value) ?? 0};`, role: "progressbar", "aria-valuenow": p.value }, c);
|
||||
var Radio = ct("input", "radio", "radio");
|
||||
var Range = ct("input", "range", "range");
|
||||
var Rating = c2("div", "rating");
|
||||
var RatingItems = (p) => [...Array(p.count)].map((_, i) => h("input", { class: cls("mask", p.class), name: p.name, type: "radio", checked: () => val(p.value) === i, onchange: () => isFunc(p.value) ? p.value(i) : p.onchange?.(i) }));
|
||||
var Skeleton = c1("div", "skeleton");
|
||||
var SkeletonText = c1("span", "skeleton skeleton-text");
|
||||
var Stack = c2("div", "stack");
|
||||
var Stats = c2("div", "stats shadow");
|
||||
var Steps = c2("ul", "steps");
|
||||
var Step = (p, c) => h("li", { ...p, class: cls("step", p.class), "data-content": p.dataContent }, c);
|
||||
var Swap = c2("label", "swap");
|
||||
var SwapToggle = (p) => h("input", { type: "checkbox", checked: () => val(p.value), onchange: (e) => isFunc(p.value) && p.value(e.target.checked), class: p.class });
|
||||
var SwapOn = c2("div", "swap-on");
|
||||
var SwapOff = c2("div", "swap-off");
|
||||
var Table = c2("table", "table");
|
||||
var Textarea = c1("textarea", "textarea");
|
||||
var Textrotate = (p, c) => h("span", { ...p, class: cls("text-rotate", p.class) }, h("span", {}, c));
|
||||
var Timeline = c2("ul", "timeline");
|
||||
var Toggle = ct("input", "toggle", "checkbox");
|
||||
var Tooltip = (p, c) => h("div", { ...p, class: cls("tooltip", p.class), "data-tip": p.tip }, c);
|
||||
var Accordion = (p) => {
|
||||
const name = p.name || rand("acc");
|
||||
return each(p.items, (it) => {
|
||||
return h("div", { class: cls("collapse", p.class) }, [
|
||||
h("input", { type: "radio", name, checked: it.open || undefined }),
|
||||
it.title ? h("div", { class: cls("collapse-title", `${it.classTitle ?? " font-semibold"}`) }, it.title) : null,
|
||||
it.content ? h("div", { class: cls("collapse-content text-sm", `${it.classContent ?? " font-semibold"}`) }, it.content) : null
|
||||
]);
|
||||
});
|
||||
};
|
||||
var Autocomplete = ({ items, value, onselect, placeholder = "...", ...props }) => {
|
||||
const query = $(val(value) || "");
|
||||
const filtered = $(() => filterBy(items, query()));
|
||||
const pick = (item) => {
|
||||
const display = getBy(item);
|
||||
const actual = typeof item === "string" ? item : item.value;
|
||||
query(display);
|
||||
if (isFunc(value))
|
||||
value(actual);
|
||||
onselect?.(item);
|
||||
hide();
|
||||
};
|
||||
return Dropdown({ class: "w-80" }, [
|
||||
h("div", { tabindex: "0", role: "button", class: "w-full" }, Input({ ...props, placeholder, value: query, left: Icon({}, "icon-[lucide--search]") })),
|
||||
DropdownContent({ class: "p-2 bg-base-100 rounded-box shadow-xl w-full max-h-60 overflow-y-auto border border-base-300 z-50" }, h("ul", { class: "menu flex-col flex-nowrap w-full p-0" }, [
|
||||
each(filtered, (item) => h("li", {}, [h("a", { onmousedown: (e) => e.preventDefault(), onclick: () => pick(item) }, getBy(item))]), "value"),
|
||||
() => filtered().length === 0 ? h("li", { class: "p-4 opacity-50 text-center" }, "Sin resultados") : null
|
||||
]))
|
||||
]);
|
||||
};
|
||||
var AvatarGroup = (p, c) => h("div", { ...p, class: `${"avatar-group -space-x-6"} ${p?.class || ""}`.trim() }, c);
|
||||
var Badge = (p, c) => h("span", { ...p, class: `${"badge"} ${p?.class || ""}`.trim() }, c);
|
||||
var Breadcrumbs = (p, c) => h("div", { ...p, class: `${"breadcrumbs"} ${p?.class || ""}`.trim() }, c);
|
||||
var Button = (p, c) => h("button", { ...p, class: `${"btn"} ${p?.class || ""}`.trim() }, c);
|
||||
var Calendar = (p) => {
|
||||
const internalDate = $(new Date);
|
||||
const hoverDate = $(null);
|
||||
const startHour = $(0);
|
||||
const endHour = $(0);
|
||||
const now = new Date;
|
||||
const todayStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
||||
const fmt = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
||||
const rangeMode = () => val(p.range) === true;
|
||||
const current = () => val(p.value);
|
||||
const selectDate = (date) => {
|
||||
const s = fmt(date);
|
||||
const v = current();
|
||||
if (rangeMode()) {
|
||||
if (!v?.start || v.start && v.end) {
|
||||
p.onChange?.({ start: s, end: null, ...p.hour && { startHour: startHour() } });
|
||||
} else {
|
||||
const start = v.start;
|
||||
const nv = s < start ? { start: s, end: start } : { start, end: s };
|
||||
if (p.hour) {
|
||||
nv.startHour = v.startHour ?? startHour();
|
||||
nv.endHour = endHour();
|
||||
}
|
||||
p.onChange?.(nv);
|
||||
}
|
||||
} else {
|
||||
p.onChange?.(p.hour ? `${s}T${String(startHour()).padStart(2, "0")}:00:00` : s);
|
||||
}
|
||||
};
|
||||
const move = (m) => {
|
||||
const d = internalDate();
|
||||
internalDate(new Date(d.getFullYear(), d.getMonth() + m, 1));
|
||||
};
|
||||
const moveYear = (y) => {
|
||||
const d = internalDate();
|
||||
internalDate(new Date(d.getFullYear() + y, d.getMonth(), 1));
|
||||
};
|
||||
const HourSlider = ({ value: hVal, onChange: onH }) => h("div", { class: "flex-1" }, [
|
||||
h("div", { class: "flex gap-2 items-center" }, [
|
||||
h("input", { type: "range", min: 0, max: 23, value: hVal, class: "range range-xs flex-1", oninput: (e) => onH(+e.target.value) }),
|
||||
h("span", { class: "text-sm font-mono min-w-[48px] text-center" }, () => String(val(hVal)).padStart(2, "0") + ":00")
|
||||
])
|
||||
let [d, hv, sh, eh] = [$(new Date), $(0), $(0), $(0)], now = new Date, F = (v) => v?.toISOString().slice(0, 10), P = (n) => (n < 10 ? "0" : "") + n, M = (m, y = 0) => d(new Date(d().getFullYear() + y, d().getMonth() + m, 1)), V = () => typeof p.value == "function" ? p.value() : p.value, G = () => typeof p.range == "function" ? p.range() : p.range, L = (dt) => {
|
||||
let s = F(dt), v = V(), r = G();
|
||||
if (!r)
|
||||
return p.onChange?.(p.hour ? `${s}T${P(sh())}:00:00` : s);
|
||||
if (!v?.start || v.end)
|
||||
return p.onChange?.({ start: s, end: null, ...p.hour && { startHour: sh() } });
|
||||
let nv = s < v.start ? { start: s, end: v.start } : { start: v.start, end: s };
|
||||
p.onChange?.({ ...nv, ...p.hour && { startHour: v.startHour ?? sh(), endHour: eh() } });
|
||||
}, I = ({ v, on }) => h("div", { class: "flex-1 flex gap-2 items-center" }, [
|
||||
h("input", { type: "range", min: 0, max: 23, value: v, class: "range range-xs", oninput: (e) => on(+e.target.value) }),
|
||||
h("span", { class: "text-sm font-mono" }, () => P(v()) + ":00")
|
||||
]);
|
||||
return h("div", {
|
||||
class: cls("p-4 bg-base-100 border border-base-300 shadow-2xl rounded-box w-80 select-none", p.class)
|
||||
}, [
|
||||
h("div", { class: "flex justify-between items-center mb-4 gap-1" }, [
|
||||
h("div", { class: "flex gap-0.5" }, [
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => moveYear(-1) }, h("span", { class: "icon-[lucide--chevrons-left]" })),
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => move(-1) }, h("span", { class: "icon-[lucide--chevron-left]" }))
|
||||
]),
|
||||
h("span", { class: "font-bold uppercase flex-1 text-center" }, () => internalDate().toLocaleString("es-ES", { month: "short", year: "numeric" })),
|
||||
h("div", { class: "flex gap-0.5" }, [
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => move(1) }, h("span", { class: "icon-[lucide--chevron-right]" })),
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => moveYear(1) }, h("span", { class: "icon-[lucide--chevrons-right]" }))
|
||||
])
|
||||
return h("div", { class: `p-4 bg-base-100 border shadow-2xl rounded-box w-80 select-none ${p.class || ""}` }, [
|
||||
h("div", { class: "flex justify-between items-center mb-4" }, [
|
||||
h("div", { class: "flex" }, [["-1y", -1, 1], ["-1m", -1, 0]].map(([_, m, y]) => h("button", { class: "btn btn-ghost btn-xs", onclick: () => M(m, y) }, h("span", { class: `icon-[lucide--chevron${y ? "s" : ""}-left]` })))),
|
||||
h("span", { class: "font-bold uppercase" }, () => d().toLocaleString("es", { month: "short", year: "numeric" })),
|
||||
h("div", { class: "flex" }, [[1, 0], [1, 1]].map(([m, y]) => h("button", { class: "btn btn-ghost btn-xs", onclick: () => M(m, y) }, h("span", { class: `icon-[lucide--chevron${y ? "s" : ""}-right]` }))))
|
||||
]),
|
||||
h("div", { class: "grid grid-cols-7 gap-1", onmouseleave: () => hoverDate(null) }, [
|
||||
...["L", "M", "X", "J", "V", "S", "D"].map((d) => h("div", { class: "text-[10px] opacity-40 font-bold text-center" }, d)),
|
||||
h("div", { class: "grid grid-cols-7 gap-1", onmouseleave: () => hv(null) }, [
|
||||
..."LMXJVSD".split("").map((l) => h("div", { class: "text-[10px] opacity-40 font-bold text-center" }, l)),
|
||||
() => {
|
||||
const d = internalDate(), y = d.getFullYear(), m = d.getMonth();
|
||||
const firstDay = new Date(y, m, 1).getDay();
|
||||
const offset = firstDay === 0 ? 6 : firstDay - 1;
|
||||
const dim = new Date(y, m + 1, 0).getDate();
|
||||
const cells = [];
|
||||
for (let i = 0;i < offset; i++)
|
||||
cells.push(h("div"));
|
||||
for (let i = 1;i <= dim; i++) {
|
||||
const date = new Date(y, m, i), ds = fmt(date);
|
||||
cells.push(h("button", {
|
||||
let y = d().getFullYear(), m = d().getMonth(), first = (new Date(y, m, 1).getDay() + 6) % 7;
|
||||
return [...Array(first).fill(h("div")), ...Array(new Date(y, m + 1, 0).getDate()).keys()].map((i) => {
|
||||
if (typeof i != "number")
|
||||
return i;
|
||||
let day = i + 1, ds = F(new Date(y, m, day)), today = F(now) == ds;
|
||||
return h("button", {
|
||||
type: "button",
|
||||
onclick: () => L(new Date(y, m, day)),
|
||||
onmouseenter: () => G() && hv(ds),
|
||||
class: () => {
|
||||
const v = current(), h2 = hoverDate();
|
||||
const isStart = typeof v === "string" ? v.split("T")[0] === ds : v?.start === ds;
|
||||
const isEnd = v?.end === ds;
|
||||
let inRange = false;
|
||||
if (rangeMode() && v?.start) {
|
||||
const start = v.start;
|
||||
if (!v.end && h2)
|
||||
inRange = ds > start && ds <= h2 || ds < start && ds >= h2;
|
||||
else if (v.end)
|
||||
inRange = ds > start && ds < v.end;
|
||||
}
|
||||
const base = "btn btn-xs p-0 aspect-square min-h-0 h-auto font-normal relative";
|
||||
const st = isStart || isEnd ? "btn-primary z-10" : inRange ? "bg-primary/20 border-none rounded-none" : "btn-ghost";
|
||||
const today = ds === todayStr ? "ring-1 ring-primary ring-inset font-black text-primary" : "";
|
||||
return cls(base, st, today);
|
||||
},
|
||||
onmouseenter: () => rangeMode() && hoverDate(ds),
|
||||
onclick: () => selectDate(date)
|
||||
}, i.toString()));
|
||||
}
|
||||
return cells;
|
||||
let v = V(), hov = hv(), s = v?.start || (typeof v == "string" ? v.slice(0, 10) : 0), isE = v?.end == ds, isS = s == ds, inR = G() && v?.start && (v.end ? ds > v.start && ds < v.end : hov && (ds > s && ds <= hov || ds < s && ds >= hov));
|
||||
return `btn btn-xs p-0 aspect-square min-h-0 h-auto font-normal relative ${isS || isE ? "btn-primary z-10" : inR ? "bg-primary/20 border-none rounded-none" : "btn-ghost"} ${today ? "ring-1 ring-primary font-black" : ""}`;
|
||||
}
|
||||
}, day);
|
||||
});
|
||||
}
|
||||
]),
|
||||
p.hour ? h("div", { class: "mt-3 pt-2 border-t border-base-300" }, rangeMode() ? h("div", { class: "flex gap-4" }, [HourSlider({ value: startHour, onChange: (h2) => startHour(h2) }), HourSlider({ value: endHour, onChange: (h2) => endHour(h2) })]) : HourSlider({ value: startHour, onChange: (h2) => startHour(h2) })) : null
|
||||
]);
|
||||
};
|
||||
var Colorpicker = (p) => {
|
||||
const current = () => val(p.value) || "#000000";
|
||||
return Dropdown({}, [
|
||||
DropdownButton({ class: "btn" }, [
|
||||
h("div", { class: "size-5 rounded-sm", style: () => `background-color: ${current()}` }),
|
||||
p.label && h("span", {}, p.label)
|
||||
]),
|
||||
DropdownContent({ class: "p-0" }, ColorPalette({ value: p.value, onchange: (c) => {
|
||||
isFunc(p.value) ? p.value(c) : p.onchange?.(c);
|
||||
} }))
|
||||
p.hour && h("div", { class: "mt-3 pt-2 border-t flex gap-4" }, G() ? [I({ v: sh, on: sh }), I({ v: eh, on: eh })] : [I({ v: sh, on: sh })])
|
||||
]);
|
||||
};
|
||||
var Card = (p, c) => h("div", { ...p, class: `${"card"} ${p?.class || ""}`.trim() }, c);
|
||||
var CardTitle = (p, c) => h("div", { ...p, class: `${"card-title"} ${p?.class || ""}`.trim() }, c);
|
||||
var CardBody = (p, c) => h("div", { ...p, class: `${"card-body"} ${p?.class || ""}`.trim() }, c);
|
||||
var CardActions = (p, c) => h("div", { ...p, class: `${"card-actions"} ${p?.class || ""}`.trim() }, c);
|
||||
var Carousel = (p, c) => h("div", { ...p, class: `${"carousel"} ${p?.class || ""}`.trim() }, c);
|
||||
var CarouselItem = (p, c) => h("div", { ...p, class: `${"carousel-item"} ${p?.class || ""}`.trim() }, c);
|
||||
var Chat = (p, c) => h("div", { ...p, class: `${"chat"} ${p?.class || ""}`.trim() }, c);
|
||||
var ChatBubble = (p, c) => h("div", { ...p, class: `${"chat-bubble"} ${p?.class || ""}`.trim() }, c);
|
||||
var ChatFooter = (p, c) => h("div", { ...p, class: `${"chat-footer"} ${p?.class || ""}`.trim() }, c);
|
||||
var ChatHeader = (p, c) => h("div", { ...p, class: `${"chat-header"} ${p?.class || ""}`.trim() }, c);
|
||||
var ChatImage = (p, c) => h("div", { ...p, class: `${"chat-image avatar"} ${p?.class || ""}`.trim() }, h("div", { class: "w-10 rounded-full" }, typeof c === "string" ? h("img", { src: c, alt: "avatar" }) : c));
|
||||
var Checkbox = (p) => h("input", { type: "checkbox", ...p, class: `${"checkbox"} ${p?.class || ""}`.trim() });
|
||||
var ColorPalette = (p) => {
|
||||
const current = () => val(p.value) || "#000000";
|
||||
const palette = [
|
||||
"#000",
|
||||
"#1A1A1A",
|
||||
"#333",
|
||||
"#4D4D4D",
|
||||
"#666",
|
||||
"#808080",
|
||||
"#B3B3B3",
|
||||
"#FFF",
|
||||
"#450a0a",
|
||||
"#7f1d1d",
|
||||
"#991b1b",
|
||||
"#b91c1c",
|
||||
"#dc2626",
|
||||
"#ef4444",
|
||||
"#f87171",
|
||||
"#fca5a5",
|
||||
"#431407",
|
||||
"#7c2d12",
|
||||
"#9a3412",
|
||||
"#c2410c",
|
||||
"#ea580c",
|
||||
"#f97316",
|
||||
"#fb923c",
|
||||
"#ffedd5",
|
||||
"#713f12",
|
||||
"#a16207",
|
||||
"#ca8a04",
|
||||
"#eab308",
|
||||
"#facc15",
|
||||
"#fde047",
|
||||
"#fef08a",
|
||||
"#fff9c4",
|
||||
"#064e3b",
|
||||
"#065f46",
|
||||
"#059669",
|
||||
"#10b981",
|
||||
"#34d399",
|
||||
"#4ade80",
|
||||
"#84cc16",
|
||||
"#d9f99d",
|
||||
"#082f49",
|
||||
"#075985",
|
||||
"#0284c7",
|
||||
"#0ea5e9",
|
||||
"#38bdf8",
|
||||
"#7dd3fc",
|
||||
"#22d3ee",
|
||||
"#cffafe",
|
||||
"#1e1b4b",
|
||||
"#312e81",
|
||||
"#4338ca",
|
||||
"#4f46e5",
|
||||
"#6366f1",
|
||||
"#818cf8",
|
||||
"#a5b4fc",
|
||||
"#e0e7ff",
|
||||
"#2e1065",
|
||||
"#4c1d95",
|
||||
"#6d28d9",
|
||||
"#7c3aed",
|
||||
"#8b5cf6",
|
||||
"#a855f7",
|
||||
"#d946ef",
|
||||
"#fae8ff"
|
||||
];
|
||||
const pick = (c) => {
|
||||
isFunc(p.value) ? p.value(c) : p.onchange?.(c);
|
||||
hide();
|
||||
};
|
||||
return h("div", {
|
||||
class: cls("p-3 bg-base-100 rounded-box shadow w-64", p.class)
|
||||
}, h("div", { class: "grid grid-cols-8 gap-1" }, palette.map((c) => h("button", {
|
||||
let L = (s) => (s || "").toLowerCase(), C = "#000,#1A1A1A,#333,#4D4D4D,#666,#808080,#B3B3B3,#FFF,#450a0a,#7f1d1d,#991b1b,#b91c1c,#dc2626,#ef4444,#f87171,#fca5a5,#431407,#7c2d12,#9a3412,#c2410c,#ea580c,#f97316,#fb923c,#ffedd5,#713f12,#a16207,#ca8a04,#eab308,#facc15,#fde047,#fef08a,#fff9c4,#064e3b,#065f46,#059669,#10b981,#34d399,#4ade80,#84cc16,#d9f99d,#082f49,#075985,#0284c7,#0ea5e9,#38bdf8,#7dd3fc,#22d3ee,#cffafe,#1e1b4b,#312e81,#4338ca,#4f46e5,#6366f1,#818cf8,#a5b4fc,#e0e7ff,#2e1065,#4c1d95,#6d28d9,#7c3aed,#8b5cf6,#a855f7,#d946ef,#fae8ff".split(",");
|
||||
return h("div", { class: `p-3 bg-base-100 rounded-box shadow w-64 ${p.class || ""}` }, h("div", { class: "grid grid-cols-8 gap-1" }, C.map((c) => h("button", {
|
||||
type: "button",
|
||||
style: `background-color: ${c}`,
|
||||
class: () => {
|
||||
const act = current().toLowerCase() === c.toLowerCase();
|
||||
return `size-6 rounded-sm cursor-pointer transition-all hover:scale-125 hover:z-10 active:scale-95 outline-none border border-black/5 p-0 min-h-0 ${act ? "ring-2 ring-offset-1 ring-primary z-10 scale-110" : ""}`;
|
||||
},
|
||||
onclick: () => {
|
||||
pick(c);
|
||||
}
|
||||
style: { background: c },
|
||||
onclick: () => (isFunc(p.value) ? p.value(c) : p.onchange?.(c), hide()),
|
||||
class: () => `size-6 rounded-sm transition-all hover:scale-125 hover:z-10 active:scale-95 border border-black/5 p-0 min-h-0 ${L(val(p.value)) == L(c) ? "ring-2 ring-offset-1 ring-primary z-10 scale-110" : ""}`
|
||||
}))));
|
||||
};
|
||||
var Datepicker = (p) => {
|
||||
const displayValue = $("");
|
||||
const rangeMode = () => val(p.range) === true;
|
||||
watch(() => {
|
||||
const v = val(p.value);
|
||||
if (!v)
|
||||
return displayValue("");
|
||||
let text = "";
|
||||
if (typeof v === "string") {
|
||||
text = p.hour && v.includes("T") ? v.replace("T", " ") : v;
|
||||
} else if (v.start && v.end) {
|
||||
const startStr = p.hour && v.startHour != null ? `${v.start} ${String(v.startHour).padStart(2, "0")}:00` : v.start;
|
||||
const endStr = p.hour && v.endHour != null ? `${v.end} ${String(v.endHour).padStart(2, "0")}:00` : v.end;
|
||||
text = `${startStr} - ${endStr}`;
|
||||
} else if (v.start) {
|
||||
const startStr = p.hour && v.startHour != null ? `${v.start} ${String(v.startHour).padStart(2, "0")}:00` : v.start;
|
||||
text = `${startStr}...`;
|
||||
}
|
||||
displayValue(text);
|
||||
});
|
||||
const handleChange = (val2) => {
|
||||
if (isFunc(p.value))
|
||||
p.value(val2);
|
||||
else
|
||||
p.onChange?.(val2);
|
||||
if (!rangeMode() || val2?.end != null)
|
||||
hide();
|
||||
};
|
||||
return Dropdown({ class: cls("w-full", p.class) }, [
|
||||
h("label", {
|
||||
tabindex: "0",
|
||||
role: "button",
|
||||
class: "input input-bordered flex items-center gap-2 cursor-pointer"
|
||||
}, [
|
||||
h("span", { class: "icon-[lucide--calendar] shrink-0" }),
|
||||
h("span", {
|
||||
class: () => `grow text-left truncate ${!displayValue() ? "opacity-50" : ""}`
|
||||
}, () => displayValue() || p.placeholder || (rangeMode() ? "Seleccionar rango..." : "Seleccionar fecha...")),
|
||||
() => displayValue() ? h("button", {
|
||||
type: "button",
|
||||
class: "btn btn-ghost btn-xs btn-circle -mr-2",
|
||||
onmousedown: (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (isFunc(p.value))
|
||||
p.value(null);
|
||||
else
|
||||
p.onChange?.(null);
|
||||
displayValue("");
|
||||
}
|
||||
}, h("span", { class: "icon-[lucide--x] opacity-50" })) : null
|
||||
]),
|
||||
DropdownContent({ class: "p-0" }, Calendar({ value: p.value, range: rangeMode(), hour: p.hour, onChange: handleChange }))
|
||||
]);
|
||||
};
|
||||
var Fileinput = (p) => {
|
||||
const files = $([]);
|
||||
const drag = $(false);
|
||||
const error = $(null);
|
||||
const maxBytes = (p.max || 2) * 1024 * 1024;
|
||||
const process = (fileList) => {
|
||||
const arr = Array.from(fileList);
|
||||
error(null);
|
||||
if (arr.some((f) => f.size > maxBytes)) {
|
||||
error(`Máx ${p.max || 2}MB`);
|
||||
return;
|
||||
}
|
||||
const updated = [...files(), ...arr];
|
||||
files(updated);
|
||||
if (isFunc(p.onselect))
|
||||
p.onselect(updated);
|
||||
else if (isFunc(p.value))
|
||||
p.value(updated);
|
||||
};
|
||||
const remove = (idx) => {
|
||||
const updated = files().filter((_, i) => i !== idx);
|
||||
files(updated);
|
||||
if (isFunc(p.onselect))
|
||||
p.onselect(updated);
|
||||
else if (isFunc(p.value))
|
||||
p.value(updated);
|
||||
};
|
||||
return h("div", { class: cls("fieldset w-full p-0", p.class) }, [
|
||||
h("label", {
|
||||
class: () => `relative flex items-center justify-between w-full h-12 px-4 border-2 border-dashed rounded-lg cursor-pointer transition-all duration-200 ${drag() ? "border-primary bg-primary/10" : "border-base-content/20 bg-base-100 hover:bg-base-200"}`,
|
||||
ondragover: (e) => {
|
||||
e.preventDefault();
|
||||
drag(true);
|
||||
},
|
||||
ondragleave: () => drag(false),
|
||||
ondrop: (e) => {
|
||||
e.preventDefault();
|
||||
drag(false);
|
||||
process(e.dataTransfer.files);
|
||||
}
|
||||
}, [
|
||||
h("div", { class: "flex items-center gap-3 w-full" }, [
|
||||
h("span", { class: "icon-[lucide--upload]" }),
|
||||
h("span", { class: "text-sm opacity-70 truncate grow text-left" }, "..."),
|
||||
h("span", { class: "text-[10px] opacity-40 shrink-0" }, `Máx ${p.max || 2}MB`)
|
||||
]),
|
||||
h("input", {
|
||||
type: "file",
|
||||
multiple: true,
|
||||
accept: p.accept || "*",
|
||||
class: "hidden",
|
||||
onchange: (e) => process(e.target.files)
|
||||
})
|
||||
]),
|
||||
() => error() && h("span", { class: "text-[10px] text-error mt-1 px-1 font-medium" }, error()),
|
||||
when(() => files().length > 0, () => h("ul", { class: "mt-2 space-y-1" }, each(files, (file, idx) => h("li", { class: "flex items-center justify-between p-1.5 pl-3 text-xs bg-base-200/50 rounded-md border border-base-300" }, [
|
||||
h("div", { class: "flex items-center gap-2 truncate" }, [
|
||||
h("span", { class: "opacity-50" }, "\uD83D\uDCC4"),
|
||||
h("span", { class: "truncate font-medium max-w-[200px]" }, file.name),
|
||||
h("span", { class: "text-[9px] opacity-40" }, `(${(file.size / 1024).toFixed(0)} KB)`)
|
||||
]),
|
||||
h("button", {
|
||||
type: "button",
|
||||
class: "btn btn-ghost btn-xs btn-circle",
|
||||
onclick: (e) => {
|
||||
e.preventDefault();
|
||||
remove(idx);
|
||||
}
|
||||
}, h("span", { class: "icon-[lucide--x]" }))
|
||||
]))))
|
||||
]);
|
||||
};
|
||||
var Input = (p) => {
|
||||
const { label: label2, icon, float, placeholder, value, left, right, rule, hint, content, ...rest } = p;
|
||||
const showPassword = $(false);
|
||||
const isPassword = p.type === "password";
|
||||
const pattern = rule ?? null;
|
||||
const inputType = () => isPassword ? val(showPassword) ? "text" : "password" : p.type || "search";
|
||||
return h("label", { class: float ? "floating-label" : "" }, [
|
||||
float ? h("span", {}, label2) : null,
|
||||
h("label", { pattern, class: () => cls("input validator", p.class) }, [
|
||||
label2 && !float ? h("span", { class: "label" }, label2) : null,
|
||||
left ?? null,
|
||||
h("input", { ...rest, type: inputType, class: "grow", pattern, placeholder: placeholder || label2 || " ", value }),
|
||||
right ?? null,
|
||||
isPassword ? Swap({ class: "ml-2" }, [
|
||||
SwapToggle({ value: showPassword, class: "swap-rotate" }),
|
||||
SwapOn({}, Icon({}, "icon-[lucide--eye]")),
|
||||
SwapOff({}, Icon({}, "icon-[lucide--eye-off]"))
|
||||
]) : null
|
||||
]),
|
||||
hint ? h("div", { class: "validator-hint" }, hint) : null
|
||||
]);
|
||||
};
|
||||
var Menu = (p) => {
|
||||
if (p.children !== undefined)
|
||||
return h("ul", { class: cls("menu", p.class), ...p }, p.children);
|
||||
const { items } = p;
|
||||
const render = (item) => item.children ? h("li", {}, h("details", { open: item.open || undefined }, [
|
||||
h("summary", {}, getBy(item)),
|
||||
h("ul", {}, each(() => val(item.children) || [], render))
|
||||
])) : h("li", {}, h("a", {
|
||||
href: item.href,
|
||||
onclick: item.onclick ? (e) => {
|
||||
if (!item.href)
|
||||
e.preventDefault();
|
||||
item.onclick(e);
|
||||
} : null
|
||||
}, getBy(item)));
|
||||
return h("ul", { class: cls("menu", p.class) }, each(() => val(items) || [], render));
|
||||
};
|
||||
var Modal = (p, c) => {
|
||||
let dialogRef = null;
|
||||
watch(() => {
|
||||
const isOpen = val(p.open);
|
||||
if (!dialogRef)
|
||||
return;
|
||||
isOpen ? dialogRef.showModal() : dialogRef.close();
|
||||
});
|
||||
const close = () => isFunc(p.open) && p.open(false);
|
||||
return h("dialog", { ...p, ref: (el) => dialogRef = el, class: "modal", onclose: close, oncancel: close }, [
|
||||
h("div", { class: cls("modal-box", p.class ?? "") }, [
|
||||
p.title && h("h3", { class: "text-lg font-bold" }, p.title),
|
||||
c,
|
||||
h("div", { class: "modal-action" }, [
|
||||
p.actions || Button({ class: "btn", onclick: close }, "Cerrar")
|
||||
])
|
||||
]),
|
||||
h("form", { method: "dialog", class: "modal-backdrop" }, [
|
||||
h("button", {}, "close")
|
||||
])
|
||||
]);
|
||||
};
|
||||
var Select = (p, c) => {
|
||||
if (c !== undefined)
|
||||
return h("select", { class: cls("select", p.class), ...p }, c);
|
||||
const { label: label2, float, placeholder, placeholderDisabled = true, value, left, right, hint, items, keyFn, ...rest } = p;
|
||||
const opts = () => {
|
||||
const raw = val(items) || [];
|
||||
const ph = placeholder ? [{ disabled: placeholderDisabled, label: placeholder, value: "" }] : [];
|
||||
return [...ph, ...raw];
|
||||
};
|
||||
return h("label", { class: float ? "floating-label" : "" }, [
|
||||
float ? h("span", {}, label2) : null,
|
||||
h("label", { class: cls("select", rest.class) }, [
|
||||
!float && label2 ? h("span", { class: "label" }, label2) : null,
|
||||
left ?? null,
|
||||
h("select", {
|
||||
value: () => val(value),
|
||||
onchange: (e) => isFunc(value) ? value(e.target.value) : rest.onchange?.(e)
|
||||
}, each(opts, (item) => {
|
||||
const val2 = getBy(item, item.value !== undefined ? "value" : undefined);
|
||||
const lab = getBy(item, "label");
|
||||
return h("option", { value: val2, disabled: item.disabled || undefined }, lab);
|
||||
})),
|
||||
right ?? null
|
||||
]),
|
||||
hint ? h("div", { class: "validator-hint" }, hint) : null
|
||||
]);
|
||||
};
|
||||
var Stat = (p) => h("div", { ...p, class: cls("stat", p.class) }, [
|
||||
p.title ? h("div", { class: "stat-title" }, p.title) : null,
|
||||
p.value ? h("div", { class: "stat-value" }, p.value) : null,
|
||||
p.desc ? h("div", { class: "stat-desc" }, p.desc) : null
|
||||
]);
|
||||
var TableItems = ({ items, columns = [], header = true }) => {
|
||||
const head = header !== false && columns.some((c) => c.label) ? h("thead", {}, h("tr", {}, columns.map((c) => h("th", { class: c.class }, c.label)))) : null;
|
||||
const body = h("tbody", {}, () => {
|
||||
const list = val(items) || [];
|
||||
return list.map((it, idx) => h("tr", {}, columns.map((c) => {
|
||||
const v = c.render ? c.render(it, idx) : it[c.key];
|
||||
return h("td", { class: c.class }, v);
|
||||
})));
|
||||
});
|
||||
return [head, body].filter(Boolean);
|
||||
};
|
||||
var Tabs = (p, c) => {
|
||||
if (!p.items) {
|
||||
const { class: className2, ...rest2 } = p;
|
||||
return h("div", { ...rest2, class: cls("tabs", className2) }, c);
|
||||
var Combo = (p, c) => Dropdown({}, [div({ tabindex: "0", role: "button" }, c), DropdownContent({ class: p?.class }, p.content)]);
|
||||
var Drawer = (p, c) => h("div", { ...p, class: `${"drawer"} ${p?.class || ""}`.trim() }, c);
|
||||
var DrawerToggle = (p) => input({ ...p, type: "checkbox", class: "drawer-toggle", checked: () => val(p.checked), onchange: (e) => isFunc(p.checked) && p.checked(e.target.checked) });
|
||||
var DrawerContent = (p, c) => h("div", { ...p, class: `${"drawer-content"} ${p?.class || ""}`.trim() }, c);
|
||||
var DrawerSide = (p, c) => h("div", { ...p, class: `${"drawer-side"} ${p?.class || ""}`.trim() }, c);
|
||||
var DrawerOverlay = (p) => label({ ...p, for: p.for, class: `${"drawer-overlay"} ${p?.class || ""}`.trim() });
|
||||
var Divider = (p) => h("div", { ...p, class: `${"divider"} ${p?.class || ""}`.trim() });
|
||||
var Dropdown = (p, c) => h("div", { ...p, class: `${"dropdown"} ${p?.class || ""}`.trim() }, c);
|
||||
var DropdownButton = (p, c) => h("div", { ...p, tabindex: "0", role: "button", class: `${"btn"} ${p?.class || ""}`.trim() }, c);
|
||||
var DropdownContent = (p, c) => h("div", { ...p, tabindex: "0", class: `${"dropdown-content"} ${p?.class || ""}`.trim() }, c);
|
||||
var Fab = (p, c) => h("div", { class: "fab" }, [h("div", { tabindex: "0", role: "button", class: `${"btn"} ${p?.class || ""}`.trim() }, Icon({}, p.icon)), c]);
|
||||
var Fieldset = (p, c) => h("fieldset", { class: `${"fieldset"} ${p?.class || ""}`.trim() }, [h("legend", { class: "fieldset-legend" }, p.label), c]);
|
||||
var FileDrag = (p, c) => h("label", {
|
||||
class: () => `relative flex items-center justify-between h-12 px-4 border-2 border-dashed rounded-lg cursor-pointer transition-all ${p.drag ? "border-primary bg-primary/10" : "border-base-content/20 bg-base-100"} ${p?.class || ""}`,
|
||||
ondragover: (e) => {
|
||||
e.preventDefault();
|
||||
p.ondrag?.(true);
|
||||
},
|
||||
ondragleave: () => p.ondrag?.(false),
|
||||
ondrop: (e) => {
|
||||
e.preventDefault();
|
||||
p.ondrag?.(false);
|
||||
p.ondrop?.(e.dataTransfer.files);
|
||||
}
|
||||
const { items, activeIndex, onClose, class: className, ...rest } = p;
|
||||
const get = (x) => isFunc(x) ? x() : x;
|
||||
const closeH = onClose || (isFunc(items) ? (idx, item) => {
|
||||
const arr = val(items);
|
||||
const newArr = arr.filter((_, i) => i !== idx);
|
||||
items(newArr);
|
||||
if (activeIndex() >= newArr.length)
|
||||
activeIndex(Math.max(0, newArr.length - 1));
|
||||
} : null);
|
||||
return h("div", { ...rest, class: cls("tabs", className) }, () => {
|
||||
const list = val(items) || [];
|
||||
return list.flatMap((it, idx) => {
|
||||
const isActive = () => activeIndex() === idx;
|
||||
const button = h("button", {
|
||||
class: () => `tab ${isActive() ? "tab-active" : ""} ${it.class || ""}`,
|
||||
onclick: (e) => {
|
||||
e.preventDefault();
|
||||
activeIndex(idx);
|
||||
it.onclick?.(e);
|
||||
}
|
||||
}, [
|
||||
getBy(it),
|
||||
it.closable ? h("span", {
|
||||
class: "ml-1 inline-flex items-center justify-center w-4 h-4 rounded-full hover:bg-base-300 text-base-content/60 hover:text-base-content cursor-pointer",
|
||||
onclick: (e) => {
|
||||
e.stopPropagation();
|
||||
closeH?.(idx, it);
|
||||
}
|
||||
}, h("span", { class: "icon-[lucide--x] w-3 h-3" })) : null
|
||||
]);
|
||||
const contentDiv = h("div", {
|
||||
class: "tab-content bg-base-100 border-base-300 p-6",
|
||||
style: () => `display: ${isActive() ? "block" : "none"};`
|
||||
}, isFunc(it.content) ? it.content() : it.content);
|
||||
return [button, contentDiv];
|
||||
});
|
||||
});
|
||||
}, c);
|
||||
var FileInput = (p) => h("input", { type: "file", multiple: true, accept: p.accept || "*", class: `${"file-input"} ${p?.class || ""}`.trim(), onchange: (e) => p.onchange?.(e.target.files) });
|
||||
var FilePreview = (p) => h("ul", { class: `mt-2 space-y-1 ${p?.class || ""}` }, p.files.map((f, i) => h("li", { class: "flex items-center justify-between p-1.5 pl-3 text-xs bg-base-200/50 rounded-md border" }, [
|
||||
h("div", { class: "flex items-center gap-2 truncate opacity-70" }, [
|
||||
h("span", {}, "\uD83D\uDCC4"),
|
||||
h("span", { class: "truncate max-w-[180px]" }, f.name),
|
||||
h("span", { class: "text-[9px] opacity-50" }, `(${~~(f.size / 1024)}KB)`)
|
||||
]),
|
||||
h("button", { class: "btn btn-ghost btn-xs btn-circle", onclick: () => p.onremove?.(i) }, h("span", { class: "icon-[lucide--x]" }))
|
||||
])));
|
||||
var FileError = (p) => h("div", { class: `text-[10px] text-error mt-1 px-1 ${p?.class || ""}` }, p.message);
|
||||
var Filter = (s, i, o, k) => o($(() => val(i).filter((i2) => String(k ? i2[k] : i2).toLowerCase().includes(val(s).toLowerCase()))));
|
||||
var Icon = (p, c) => h("span", { ...p, class: `${c ?? ""} ${p?.class || ""}`.trim() });
|
||||
var Indicator = (p, c) => h("div", { ...p, class: `${"indicator"} ${p?.class || ""}`.trim() }, [p.value && h("span", { class: `${"indicator-item badge"} ${p?.class || ""}`.trim() }, p.value), c]);
|
||||
var Input = (p) => h("input", { ...p, class: `${"input"} ${p?.class || ""}`.trim() });
|
||||
var InputPass = (p) => {
|
||||
const show = $(false);
|
||||
return [
|
||||
Input({ ...p, type: show() ? "text" : "password" }),
|
||||
Swap({ class: "ml-2" }, [SwapToggle({ value: show, class: "swap-rotate" }), SwapOn({}, Icon({}, "icon-[lucide--eye]")), SwapOff({}, Icon({}, "icon-[lucide--eye-off]"))])
|
||||
];
|
||||
};
|
||||
var Toast = (message, type = "alert-success", duration = 3500) => {
|
||||
let container = document.getElementById("sigpro-toast-container");
|
||||
if (!container) {
|
||||
container = h("div", { id: "sigpro-toast-container", class: "fixed top-0 right-0 z-[9999] p-4 flex flex-col items-end gap-2 pointer-events-none" });
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
const host = h("div", { style: "display: contents" });
|
||||
container.appendChild(host);
|
||||
let closeFn, timer, enterTimer;
|
||||
const ToastComponent = () => {
|
||||
const visible = $(false);
|
||||
const leaving = $(false);
|
||||
closeFn = () => {
|
||||
if (leaving())
|
||||
return;
|
||||
clearTimeout(timer);
|
||||
clearTimeout(enterTimer);
|
||||
leaving(true);
|
||||
setTimeout(() => {
|
||||
instance.destroy();
|
||||
host.remove();
|
||||
if (!container.hasChildNodes())
|
||||
container.remove();
|
||||
}, 300);
|
||||
};
|
||||
enterTimer = setTimeout(() => visible(true), 0);
|
||||
const content = typeof message === "function" ? val(message) : message;
|
||||
const msgNode = typeof content === "string" ? h("span", {}, content) : content;
|
||||
var InputHint = (p, c) => h("div", { ...p, class: `${"validator-hint"} ${p?.class || ""}`.trim() }, c);
|
||||
var Kbd = (p, c) => h("kbd", { ...p, class: `${"kbd"} ${p?.class || ""}`.trim() }, c);
|
||||
var Label = (p, c) => h("span", { ...p, class: `${"label"} ${p?.class || ""}`.trim() }, c);
|
||||
var LabelFloating = (p, c) => h("label", { ...p, class: `${"floating-label"} ${p?.class || ""}`.trim() }, c);
|
||||
var LabelInput = (p, c) => h("label", { ...p, class: `${"input"} ${p?.class || ""}`.trim() }, c);
|
||||
var LabelSelect = (p, c) => h("label", { ...p, class: `${"select"} ${p?.class || ""}`.trim() }, c);
|
||||
var List = (p, c) => h("ul", { ...p, class: `${"list"} ${p?.class || ""}`.trim() }, c);
|
||||
var ListRows = (p) => () => (val(p.items) || []).map((item, idx) => h("li", { class: `${"list-row"} ${p?.class || ""} ${item?.class || ""}`.trim() }, typeof p.render === "function" ? p.render(item, idx) : item));
|
||||
var Menu = (p, c) => ul({ ...p, class: `${"menu"} ${p?.class || ""}`.trim() }, c);
|
||||
var MenuTitle = (p, c) => li({ ...p, class: `${"menu-title"} ${p?.class || ""}`.trim() }, c);
|
||||
var MenuItem = (p) => li({}, a({ onmousedown: (e) => e.preventDefault(), class: p?.class || "", onclick: p.onclick }, p.label));
|
||||
var Modal = (p, c) => h("dialog", { ...p, class: `${"modal"} ${p?.class || ""}`.trim() }, c);
|
||||
var ModalBox = (p, c) => h("div", { ...p, class: `${"modal-box"} ${p?.class || ""}`.trim() }, c);
|
||||
var ModalAction = (p, c) => h("div", { ...p, class: `${"modal-action"} ${p?.class || ""}`.trim() }, c);
|
||||
var ModalBackdrop = (p) => h("form", { method: "dialog", class: "modal-backdrop" }, [h("button", {}, "close")]);
|
||||
var ModalClose = (p) => h("form", { method: "dialog" }, [h("button", { ...p, class: `${"btn btn-sm btn-circle btn-ghost absolute right-2 top-2"} ${p?.class || ""}`.trim() }, "✕")]);
|
||||
var Loading = (p, c) => h("span", { ...p, class: `${"loading loading-spinner"} ${p?.class || ""}`.trim() }, c);
|
||||
var Navbar = (p, c) => h("div", { ...p, class: `${"navbar"} ${p?.class || ""}`.trim() }, c);
|
||||
var Progress = (p) => h("progress", { ...p, class: `${"progress"} ${p?.class || ""}`.trim() });
|
||||
var Radial = (p, c) => h("div", { class: `${"radial-progress"} ${p?.class || ""}`.trim(), style: `--value:${val(p.value) ?? 0};`, role: "progressbar", "aria-valuenow": p.value }, c);
|
||||
var Radio = (p) => h("input", { type: "radio", ...p, class: `${"radio"} ${p?.class || ""}`.trim() });
|
||||
var Range = (p) => h("input", { type: "range", ...p, class: `${"range"} ${p?.class || ""}`.trim() });
|
||||
var Rating = (p, c) => h("div", { ...p, class: `${"rating"} ${p?.class || ""}`.trim() }, c);
|
||||
var RatingItems = (p) => [...Array(p.count)].map((_, i) => h("input", { class: `${"mask"} ${p?.class || ""}`.trim(), name: p.name, type: "radio", checked: () => val(p.value) === i, onchange: () => isFunc(p.value) ? p.value(i) : p.onchange?.(i) }));
|
||||
var Select = (p, c) => h("select", { ...p, class: `${"select"} ${p?.class || ""}`.trim() }, c);
|
||||
var SelectOption = (p, c) => h("option", { ...p, class: p?.class || "" }, c);
|
||||
var Skeleton = (p) => h("div", { ...p, class: `${"skeleton"} ${p?.class || ""}`.trim() });
|
||||
var SkeletonText = (p) => h("span", { ...p, class: `${"skeleton skeleton-text"} ${p?.class || ""}`.trim() });
|
||||
var Stack = (p, c) => h("div", { ...p, class: `${"stack"} ${p?.class || ""}`.trim() }, c);
|
||||
var Stats = (p, c) => h("div", { ...p, class: `${"stats shadow"} ${p?.class || ""}`.trim() }, c);
|
||||
var Stat = (p, c) => h("div", { ...p, class: `${"stat"} ${p?.class || ""}`.trim() }, c);
|
||||
var StatFigure = (p, c) => h("div", { ...p, class: `${"stat-figure"} ${p?.class || ""}`.trim() }, c);
|
||||
var StatTitle = (p, c) => h("div", { ...p, class: `${"stat-title"} ${p?.class || ""}`.trim() }, c);
|
||||
var StatValue = (p, c) => h("div", { ...p, class: `${"stat-value"} ${p?.class || ""}`.trim() }, c);
|
||||
var StatDesc = (p, c) => h("div", { ...p, class: `${"stat-desc"} ${p?.class || ""}`.trim() }, c);
|
||||
var Steps = (p, c) => h("ul", { ...p, class: `${"steps"} ${p?.class || ""}`.trim() }, c);
|
||||
var Step = (p, c) => h("li", { ...p, class: `${"step"} ${p?.class || ""}`.trim(), "data-content": p.dataContent }, c);
|
||||
var Swap = (p, c) => h("label", { ...p, class: `${"swap"} ${p?.class || ""}`.trim() }, c);
|
||||
var SwapToggle = (p) => h("input", { type: "checkbox", checked: () => val(p.value), onchange: (e) => isFunc(p.value) && p.value(e.target.checked), class: p.class });
|
||||
var SwapOn = (p, c) => h("div", { ...p, class: `${"swap-on"} ${p?.class || ""}`.trim() }, c);
|
||||
var SwapOff = (p, c) => h("div", { ...p, class: `${"swap-off"} ${p?.class || ""}`.trim() }, c);
|
||||
var Tabs = (p, c) => div({ ...p, class: `${"tabs"} ${p?.class || ""}`.trim() }, c);
|
||||
var Tab = (p) => {
|
||||
const close = () => p.tabs?.(p.tabs().filter((_, idx) => idx !== p.index));
|
||||
return [
|
||||
h("input", { type: "radio", name: p.name, class: `${"tab"} ${p?.class || ""}`.trim(), checked: p.checked || undefined }),
|
||||
div({ class: `tab-content ${p?.classContent || ""}`.trim() }, p.content),
|
||||
p.closable ? span({ class: "absolute top-2 right-2 cursor-pointer", onclick: (e) => {
|
||||
e.stopPropagation();
|
||||
close();
|
||||
} }, "✕") : null
|
||||
];
|
||||
};
|
||||
var Table = (p, c) => h("table", { ...p, class: `${"table"} ${p?.class || ""}`.trim() }, c);
|
||||
var TableHead = (p, c) => h("thead", { ...p, class: p?.class || "" }, c);
|
||||
var TableBody = (p, c) => h("tbody", { ...p, class: p?.class || "" }, c);
|
||||
var TableFoot = (p, c) => h("tfoot", { ...p, class: p?.class || "" }, c);
|
||||
var TableRow = (p, c) => h("tr", { ...p, class: p?.class || "" }, c);
|
||||
var TableTh = (p, c) => h("th", { ...p, class: p?.class || "" }, c);
|
||||
var TableTd = (p, c) => h("td", { ...p, class: p?.class || "" }, c);
|
||||
var Textarea = (p) => h("textarea", { ...p, class: `${"textarea"} ${p?.class || ""}`.trim() });
|
||||
var Textrotate = (p, c) => h("span", { ...p, class: `${"text-rotate"} ${p?.class || ""}`.trim() }, h("span", {}, c));
|
||||
var Timeline = (p, c) => h("ul", { ...p, class: `${"timeline"} ${p?.class || ""}`.trim() }, c);
|
||||
var Toast = (m, t = "alert-success", d = 3500) => {
|
||||
let C = document.getElementById("stc"), T, E, w = h("div", { style: "display:contents" });
|
||||
if (!C)
|
||||
document.body.append(C = h("div", { id: "stc", class: "fixed top-0 right-0 z-[9999] p-4 flex flex-col items-end gap-2 pointer-events-none" }));
|
||||
C.append(w);
|
||||
const i = mount(() => {
|
||||
let v = $(0), l = $(0);
|
||||
E = () => l() || (l(1), clearTimeout(T), setTimeout(() => (i.destroy(), w.remove(), C.firstChild || C.remove()), 300));
|
||||
setTimeout(() => v(1));
|
||||
return h("div", {
|
||||
class: () => {
|
||||
const base = `alert alert-soft ${type} shadow-lg transition-all duration-300 inline-flex w-auto whitespace-nowrap pointer-events-auto`;
|
||||
if (leaving())
|
||||
return `${base} translate-x-full opacity-0`;
|
||||
if (visible())
|
||||
return `${base} translate-x-0 opacity-100`;
|
||||
return `${base} translate-x-10 opacity-0`;
|
||||
}
|
||||
class: () => `alert alert-soft ${t} shadow-lg transition-all duration-300 inline-flex w-auto pointer-events-auto ${l() ? "translate-x-full opacity-0" : v() ? "translate-x-0 opacity-100" : "translate-x-10 opacity-0"}`
|
||||
}, [
|
||||
msgNode,
|
||||
h("button", {
|
||||
class: "btn btn-xs btn-circle btn-ghost",
|
||||
onclick: closeFn
|
||||
}, h("span", { class: "icon-[lucide--x]" }))
|
||||
typeof m == "function" ? m() : typeof m == "string" ? h("span", m) : m,
|
||||
h("button", { class: "btn btn-xs btn-circle btn-ghost", onclick: E }, h("span", { class: "icon-[lucide--x]" }))
|
||||
]);
|
||||
};
|
||||
const instance = mount(ToastComponent, host);
|
||||
if (duration > 0)
|
||||
timer = setTimeout(closeFn, duration);
|
||||
return closeFn;
|
||||
}, w);
|
||||
if (d > 0)
|
||||
T = setTimeout(E, d);
|
||||
return E;
|
||||
};
|
||||
var Toggle = (p) => h("input", { type: "checkbox", ...p, class: `${"toggle"} ${p?.class || ""}`.trim() });
|
||||
var Tooltip = (p, c) => h("div", { ...p, class: `${"tooltip"} ${p?.class || ""}`.trim(), "data-tip": p.tip }, c);
|
||||
export {
|
||||
val,
|
||||
rand,
|
||||
hide,
|
||||
getBy,
|
||||
filterBy,
|
||||
cls,
|
||||
Tooltip,
|
||||
Toggle,
|
||||
Toast,
|
||||
@@ -635,8 +222,14 @@ export {
|
||||
Textrotate,
|
||||
Textarea,
|
||||
Tabs,
|
||||
TableItems,
|
||||
TableTh,
|
||||
TableTd,
|
||||
TableRow,
|
||||
TableHead,
|
||||
TableFoot,
|
||||
TableBody,
|
||||
Table,
|
||||
Tab,
|
||||
SwapToggle,
|
||||
SwapOn,
|
||||
SwapOff,
|
||||
@@ -644,10 +237,15 @@ export {
|
||||
Steps,
|
||||
Step,
|
||||
Stats,
|
||||
StatValue,
|
||||
StatTitle,
|
||||
StatFigure,
|
||||
StatDesc,
|
||||
Stat,
|
||||
Stack,
|
||||
SkeletonText,
|
||||
Skeleton,
|
||||
SelectOption,
|
||||
Select,
|
||||
RatingItems,
|
||||
Rating,
|
||||
@@ -656,16 +254,32 @@ export {
|
||||
Radial,
|
||||
Progress,
|
||||
Navbar,
|
||||
ModalClose,
|
||||
ModalBox,
|
||||
ModalBackdrop,
|
||||
ModalAction,
|
||||
Modal,
|
||||
MenuTitle,
|
||||
MenuItem,
|
||||
Menu,
|
||||
Loading,
|
||||
ListRows,
|
||||
List,
|
||||
LabelSelect,
|
||||
LabelInput,
|
||||
LabelFloating,
|
||||
Label,
|
||||
Kbd,
|
||||
InputPass,
|
||||
InputHint,
|
||||
Input,
|
||||
Indicator,
|
||||
Icon,
|
||||
Fileinput,
|
||||
Filter,
|
||||
FilePreview,
|
||||
FileInput,
|
||||
FileError,
|
||||
FileDrag,
|
||||
Fieldset,
|
||||
Fab,
|
||||
DropdownContent,
|
||||
@@ -677,8 +291,7 @@ export {
|
||||
DrawerContent,
|
||||
Drawer,
|
||||
Divider,
|
||||
Datepicker,
|
||||
Colorpicker,
|
||||
Combo,
|
||||
ColorPalette,
|
||||
Checkbox,
|
||||
ChatImage,
|
||||
@@ -698,7 +311,9 @@ export {
|
||||
Badge,
|
||||
AvatarGroup,
|
||||
Avatar,
|
||||
Autocomplete,
|
||||
Alert,
|
||||
AccordionTitle,
|
||||
AccordionRadio,
|
||||
AccordionContent,
|
||||
Accordion
|
||||
};
|
||||
|
||||
2
dist/sigpro-ui.esm.min.js
vendored
2
dist/sigpro-ui.esm.min.js
vendored
File diff suppressed because one or more lines are too long
1634
dist/sigpro-ui.js
vendored
1634
dist/sigpro-ui.js
vendored
File diff suppressed because it is too large
Load Diff
4
dist/sigpro-ui.min.css
vendored
4
dist/sigpro-ui.min.css
vendored
File diff suppressed because one or more lines are too long
8
dist/sigpro-ui.min.js
vendored
8
dist/sigpro-ui.min.js
vendored
File diff suppressed because one or more lines are too long
835
docs/demo.md
835
docs/demo.md
File diff suppressed because it is too large
Load Diff
@@ -67,7 +67,8 @@
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4.13.0/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sigpro@latest/dist/sigpro.min.js"></script>
|
||||
<!-- <script src="https://cdn.jsdelivr.net/npm/sigpro@latest/dist/sigpro.min.js"></script> -->
|
||||
<script src="./sigpro.js"></script>
|
||||
<script src="./sigpro-ui.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
4
docs/sigpro-ui.min.css
vendored
4
docs/sigpro-ui.min.css
vendored
File diff suppressed because one or more lines are too long
8
docs/sigpro-ui.min.js
vendored
8
docs/sigpro-ui.min.js
vendored
File diff suppressed because one or more lines are too long
250
docs/sigpro.js
Normal file
250
docs/sigpro.js
Normal file
@@ -0,0 +1,250 @@
|
||||
const isFunc = f => typeof f == "function";
|
||||
const isObj = o => o && typeof o == "object";
|
||||
const isArr = Array.isArray;
|
||||
const doc = typeof document < "u" ? document : null;
|
||||
const txt = s => doc.createTextNode(s == null ? "" : String(s));
|
||||
const toNd = n => n?._rt ? n._cnt : (n instanceof Node ? n : txt(n));
|
||||
const Fragment = p => p.children;
|
||||
const val = v => isFunc(v) ? v() : v;
|
||||
|
||||
let aEff = null, aOwn = null, isFlushing = 0, bDepth = 0;
|
||||
const eQ = new Set(), MOUNTED = new WeakMap();
|
||||
|
||||
const SVG_NS = "http://www.w3.org/2000/svg", XLINK = "http://www.w3.org/1999/xlink";
|
||||
const SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
||||
const DANG_ATTR = new Set(["src","href","formaction","action","background","code","archive"]);
|
||||
|
||||
const clr = s => { if(s){ s.forEach(f => f()); s.clear(); } };
|
||||
const dispose = e => {
|
||||
if (!e || e._x) return;
|
||||
e._x = 1;
|
||||
let st = [e], c;
|
||||
while ((c = st.pop())) {
|
||||
clr(c._c);
|
||||
if (c._ch) { c._ch.forEach(x => st.push(x)); c._ch.clear(); }
|
||||
if (c._d) { c._d.forEach(d => d.delete(c)); c._d.clear(); }
|
||||
}
|
||||
};
|
||||
|
||||
const onUnmount = f => aOwn && (aOwn._c ||= new Set()).add(f);
|
||||
const untrack = f => { let p = aEff; aEff = null; try { return f() } finally { aEff = p } };
|
||||
|
||||
const createEffect = (f, isC = 0) => {
|
||||
const e = () => {
|
||||
if (e._x) return;
|
||||
if (e._d) e._d.forEach(s => s.delete(e));
|
||||
clr(e._c);
|
||||
let pE = aEff, pO = aOwn;
|
||||
aEff = aOwn = e;
|
||||
try { return e._res = f(); }
|
||||
catch (err) { console.error("[SigPro]", err); }
|
||||
finally { aEff = pE; aOwn = pO; }
|
||||
};
|
||||
e._d = e._c = e._ch = null;
|
||||
e._x = 0; e._iC = isC;
|
||||
e._dp = aEff ? aEff._dp + 1 : 0;
|
||||
e._m = []; e._p = aOwn;
|
||||
if (aOwn) (aOwn._ch ||= new Set()).add(e);
|
||||
return e;
|
||||
};
|
||||
|
||||
const flush = () => {
|
||||
if (isFlushing) return;
|
||||
isFlushing = 1;
|
||||
let q = [...eQ].sort((a, b) => a._dp - b._dp);
|
||||
eQ.clear();
|
||||
for (let e of q) if (!e._x) e();
|
||||
isFlushing = 0;
|
||||
};
|
||||
|
||||
const batch = f => {
|
||||
bDepth++;
|
||||
try { return f() } finally { if (!--bDepth && eQ.size && !isFlushing) flush() }
|
||||
};
|
||||
|
||||
const trkUpd = (s, trg = 0) => {
|
||||
if (!trg && aEff && !aEff._x) {
|
||||
s.add(aEff);
|
||||
(aEff._d ||= new Set()).add(s);
|
||||
} else if (trg && s.size) {
|
||||
let q = 0;
|
||||
for (let e of s) {
|
||||
if (e === aEff || e._x) continue;
|
||||
if (e._iC) { e._dt = 1; if (e._sb) trkUpd(e._sb, 1); }
|
||||
else { eQ.add(e); q = 1; }
|
||||
}
|
||||
if (q && !isFlushing && !bDepth) queueMicrotask(flush);
|
||||
}
|
||||
};
|
||||
|
||||
const $ = (v, k = null) => {
|
||||
let s = new Set();
|
||||
if (isFunc(v)) {
|
||||
let c, cp = () => {
|
||||
if (cp._dt) {
|
||||
let p = aEff; aEff = cp;
|
||||
try { let n = v(); if (!Object.is(c, n)) { c = n; trkUpd(s, 1); } }
|
||||
finally { aEff = p; }
|
||||
cp._dt = 0;
|
||||
}
|
||||
trkUpd(s); return c;
|
||||
};
|
||||
cp._iC = cp._dt = 1; cp._sb = s; cp._d = null; cp._x = 0;
|
||||
return cp;
|
||||
}
|
||||
if (k) try { v = JSON.parse(localStorage.getItem(k)) ?? v } catch(e){}
|
||||
return (...a) => {
|
||||
if (a.length) {
|
||||
let n = isFunc(a[0]) ? a[0](v) : a[0];
|
||||
if (!Object.is(v, n)) { v = n; if (k) localStorage.setItem(k, JSON.stringify(v)); trkUpd(s, 1); }
|
||||
}
|
||||
trkUpd(s); return v;
|
||||
};
|
||||
};
|
||||
|
||||
const watch = (src, cb) => {
|
||||
let e = createEffect(cb ? () => { let v = isArr(src) ? src.map(s=>s()) : src(); untrack(() => cb(v)) } : src);
|
||||
e(); return () => dispose(e);
|
||||
};
|
||||
|
||||
const clnNd = n => {
|
||||
if (!n) return;
|
||||
clr(n._c);
|
||||
if (n._oE) dispose(n._oE);
|
||||
if (n.childNodes) n.childNodes.forEach(clnNd);
|
||||
};
|
||||
|
||||
const valAtt = (k, v) => (v == null || v === false) ? null :
|
||||
(DANG_ATTR.has(k) || k.startsWith("on")) && /^\s*(javascript|data|vbscript):/i.test(String(v)) ? '#' : v;
|
||||
|
||||
const h = (tag, prp = {}, ch = []) => {
|
||||
if (prp instanceof Node || isArr(prp) || !isObj(prp)) { ch = prp; prp = {}; }
|
||||
|
||||
if (isFunc(tag)) {
|
||||
let e = createEffect(() => e._res = tag(prp, { children: ch, emit: (ev, ...a) => prp[`on${ev[0].toUpperCase()}${ev.slice(1)}`]?.(...a) }));
|
||||
e();
|
||||
if (e._res == null) return null;
|
||||
let nd = e._res instanceof Node || (isArr(e._res) && e._res.every(n => n instanceof Node)) ? e._res : txt(e._res);
|
||||
let att = n => { if (isObj(n) && !n._rt) { n._m = e._m || []; n._c = e._c || new Set(); n._oE = e; } };
|
||||
isArr(nd) ? nd.forEach(att) : att(nd);
|
||||
return nd;
|
||||
}
|
||||
|
||||
let isS = SVG_TAGS.has(tag), el = isS ? doc.createElementNS(SVG_NS, tag) : doc.createElement(tag);
|
||||
el._c = new Set();
|
||||
|
||||
for (let k in prp) {
|
||||
let v = prp[k];
|
||||
if (k === "ref") { isFunc(v) ? v(el) : (v.current = el); continue; }
|
||||
if (isS && k.startsWith("xlink:")) {
|
||||
let cv = valAtt(k.slice(6), v);
|
||||
cv == null ? el.removeAttributeNS(XLINK, k.slice(6)) : el.setAttributeNS(XLINK, k.slice(6), cv);
|
||||
continue;
|
||||
}
|
||||
if (k.startsWith("on")) {
|
||||
let ev = k.slice(2).toLowerCase(); el.addEventListener(ev, v);
|
||||
let off = () => el.removeEventListener(ev, v); el._c.add(off); onUnmount(off);
|
||||
} else if (isFunc(v)) {
|
||||
let e = createEffect(() => {
|
||||
let r = valAtt(k, v());
|
||||
if (k === "class") el.className = r || "";
|
||||
else if (r == null) el.removeAttribute(k);
|
||||
else if (k === "style" && typeof r == "string") el.setAttribute("style", r);
|
||||
else if (k in el && !isS) el[k] = r;
|
||||
else el.setAttribute(k, r === true ? "" : r);
|
||||
});
|
||||
e(); el._c.add(() => dispose(e)); onUnmount(() => dispose(e));
|
||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||
el.addEventListener(k === "checked" ? "change" : "input", ev => v(ev.target[k]));
|
||||
}
|
||||
} else {
|
||||
let r = valAtt(k, v);
|
||||
if (r != null) {
|
||||
if (k === "style" && typeof r == "string") el.setAttribute("style", r);
|
||||
else if (k in el && !isS) el[k] = r;
|
||||
else el.setAttribute(k, r === true ? "" : r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const app = c => {
|
||||
if (isArr(c)) return c.forEach(app);
|
||||
if (isFunc(c)) {
|
||||
let anc = txt(""), cur = []; el.appendChild(anc);
|
||||
let e = createEffect(() => {
|
||||
let r = c(), nxt = (isArr(r) ? r : [r]).map(toNd), ref = anc;
|
||||
cur.forEach(n => { n._rt ? n._del() : clnNd(n); if (n.parentNode) n.remove(); });
|
||||
for (let i = nxt.length - 1; i >= 0; i--) {
|
||||
let nd = nxt[i];
|
||||
if (nd.parentNode !== ref.parentNode) ref.parentNode?.insertBefore(nd, ref);
|
||||
if (nd._m) nd._m.forEach(f => f()); ref = nd;
|
||||
}
|
||||
cur = nxt;
|
||||
});
|
||||
e(); el._c.add(() => dispose(e)); onUnmount(() => dispose(e));
|
||||
} else {
|
||||
let nd = toNd(c); el.appendChild(nd);
|
||||
if (nd._m) nd._m.forEach(f => f());
|
||||
}
|
||||
};
|
||||
app(ch); return el;
|
||||
};
|
||||
|
||||
const render = rFn => {
|
||||
let c = new Set(), pO = aOwn, pE = aEff, cnt = doc.createElement("div");
|
||||
cnt.style.display = "contents"; cnt.setAttribute("role", "presentation");
|
||||
aOwn = { _c: c }; aEff = null;
|
||||
const pRes = r => {
|
||||
if (!r) return;
|
||||
if (r._rt) { c.add(r._del); cnt.appendChild(r._cnt); }
|
||||
else if (isArr(r)) r.forEach(pRes);
|
||||
else cnt.appendChild(r instanceof Node ? r : txt(r));
|
||||
};
|
||||
try { pRes(rFn({ onCleanup: f => c.add(f) })); } finally { aOwn = pO; aEff = pE; }
|
||||
return { _rt: 1, _cnt: cnt, _del: () => { clr(c); clnNd(cnt); cnt.remove(); } };
|
||||
};
|
||||
|
||||
const when = (c, Y, N = null) => {
|
||||
let anc = txt(""), rt = h("div", { style: "display:contents" }, [anc]), v;
|
||||
watch(() => !!val(c), s => {
|
||||
if (v) { v._del(); v = null; }
|
||||
let ct = s ? Y : N;
|
||||
if (ct) { v = render(() => val(ct)); rt.insertBefore(v._cnt, anc); }
|
||||
});
|
||||
onUnmount(() => v?._del()); return rt;
|
||||
};
|
||||
|
||||
const each = (s, fn, kF) => {
|
||||
let anc = txt(""), rt = h("div", { style: "display:contents" }, [anc]), cch = new Map();
|
||||
watch(() => val(s) || [], it => {
|
||||
let nCc = new Map(), nOd = [];
|
||||
for (let i = 0, l = (it||[]).length; i < l; i++) {
|
||||
let t = it[i], k = kF ? (t?.[kF] ?? i) : (t?.id ?? i), v = cch.get(k);
|
||||
if (!v) v = render(() => fn(t, i)); else cch.delete(k);
|
||||
nCc.set(k, v); nOd.push(v);
|
||||
}
|
||||
cch.forEach(v => v._del());
|
||||
let ref = anc;
|
||||
for (let i = nOd.length - 1; i >= 0; i--) {
|
||||
let nd = nOd[i]._cnt;
|
||||
if (nd.nextSibling !== ref) rt.insertBefore(nd, ref); ref = nd;
|
||||
}
|
||||
cch = nCc;
|
||||
});
|
||||
return rt;
|
||||
};
|
||||
|
||||
const mount = (c, tgt) => {
|
||||
let t = typeof tgt == "string" ? doc.querySelector(tgt) : tgt;
|
||||
if (!t) return;
|
||||
if (MOUNTED.has(t)) MOUNTED.get(t)._del();
|
||||
let i = render(isFunc(c) ? c : () => c);
|
||||
t.replaceChildren(i._cnt); MOUNTED.set(t, i); return i;
|
||||
};
|
||||
|
||||
if (typeof window < "u") {
|
||||
"a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video"
|
||||
.split(" ").forEach(t => window[t] = (...args) => h(t, ...args));
|
||||
}
|
||||
|
||||
export { $, watch, batch, h, Fragment, render, mount, when, each, onUnmount, val, isArr, isFunc, isObj };
|
||||
13
package.json
13
package.json
@@ -19,9 +19,6 @@
|
||||
"script": "./dist/sigpro-ui.min.js",
|
||||
"types": "./index.d.ts"
|
||||
},
|
||||
"./editor": {
|
||||
"import": "./dist/sigpro-ui.editor.esm.js"
|
||||
},
|
||||
"./css": "./dist/sigpro-ui.min.css"
|
||||
},
|
||||
"files": [
|
||||
@@ -48,19 +45,17 @@
|
||||
"build:js:iife:min": "esbuild ./src/build_umd.js --bundle --outfile=./dist/sigpro-ui.min.js --format=iife --global-name=spui --minify --external:sigpro=window",
|
||||
"build:js:esm": "bun build ./src/build_esm.js --bundle --outfile=./dist/sigpro-ui.esm.js --format=esm --external sigpro",
|
||||
"build:js:esm:min": "bun build ./src/build_esm.js --bundle --outfile=./dist/sigpro-ui.esm.min.js --format=esm --minify --external sigpro",
|
||||
"build:js:editor:esm": "bun build ./src/build_editor.js --bundle --outfile=./dist/sigpro-ui.editor.esm.js --format=esm --external sigpro",
|
||||
"build:js:editor:esm:min": "bun build ./src/build_editor.js --bundle --outfile=./dist/sigpro-ui.editor.esm.min.js --format=esm --minify --external sigpro",
|
||||
"copy:docs": "cp dist/sigpro-ui.min.css dist/sigpro-ui.min.js docs/",
|
||||
"build": "bun run clean && bun run build:css && bun run build:cssmin && bun run build:js:iife && bun run build:js:iife:min && bun run build:js:esm && bun run build:js:esm:min && bun run build:js:editor:esm && bun run build:js:editor:esm:min && bun run copy:docs",
|
||||
"build": "bun run clean && bun run build:css && bun run build:cssmin && bun run build:js:iife && bun run build:js:iife:min && bun run build:js:esm && bun run build:js:esm:min && bun run copy:docs",
|
||||
"docs": "bun x serve docs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.465",
|
||||
"@iconify/json": "^2.2.471",
|
||||
"@iconify/tailwind4": "^1.2.3",
|
||||
"@tailwindcss/cli": "^4.2.4",
|
||||
"@tailwindcss/cli": "^4.3.0",
|
||||
"daisyui": "^5.5.19",
|
||||
"esbuild": "^0.28.0",
|
||||
"tailwindcss": "^4.2.4"
|
||||
"tailwindcss": "^4.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"sigpro": "git+http://gitea:3000/natxocc/sigpro"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './editor.js'
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as All from './sigpro-ui.js';
|
||||
import * as Edt from './editor.js';
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
Object.assign(window, All, Edt)
|
||||
Object.assign(window, All)
|
||||
}
|
||||
189
src/editor.js
189
src/editor.js
@@ -1,189 +0,0 @@
|
||||
import { $, isFunc, h } from "sigpro"
|
||||
import { val, cls } from "./sigpro-ui.js"
|
||||
|
||||
export const Editor = (p) => {
|
||||
const { value, class: extraClass } = p
|
||||
let editorRef = null
|
||||
let savedRange = null
|
||||
const isSource = $(false)
|
||||
const source = $("")
|
||||
const count = $(0)
|
||||
const refreshTick = $(0)
|
||||
const showEmojis = $(false)
|
||||
const emojis = ["😀", "😊", "😉", "🧐", "😮", "🤔", "😅", "😂", "😍", "😘", "🥰", "👍", "👎", "👌", "🤝", "🤞", "👋", "👏", "🙌", "🙏", "💪", "☝️", "👇", "👈", "👉", "🖕", "✅", "⚠️", "🚀", "📢", "✉️", "❤️"]
|
||||
const saveSelection = () => {
|
||||
const sel = window.getSelection()
|
||||
if (sel.getRangeAt && sel.rangeCount) savedRange = sel.getRangeAt(0)
|
||||
}
|
||||
const restoreSelection = () => {
|
||||
if (savedRange) {
|
||||
const sel = window.getSelection()
|
||||
sel.removeAllRanges()
|
||||
sel.addRange(savedRange)
|
||||
}
|
||||
}
|
||||
const triggerRefresh = () => {
|
||||
refreshTick(refreshTick() + 1)
|
||||
if (editorRef) count(editorRef.innerText.length)
|
||||
}
|
||||
const notify = () => {
|
||||
if (!editorRef) return
|
||||
const html = editorRef.innerHTML
|
||||
if (isFunc(value)) value(html)
|
||||
else p.onchange?.(html)
|
||||
triggerRefresh()
|
||||
}
|
||||
const exec = (cmd, val = null) => {
|
||||
if (!editorRef) return
|
||||
editorRef.focus()
|
||||
if (savedRange) restoreSelection()
|
||||
document.execCommand(cmd, false, val)
|
||||
savedRange = null
|
||||
notify()
|
||||
}
|
||||
const openLightbox = (src) => {
|
||||
const overlay = document.createElement('div')
|
||||
overlay.style = `position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);z-index:9999;display:flex;align-items:center;justify-content:center;cursor:zoom-out;`
|
||||
const img = document.createElement('img')
|
||||
img.src = src
|
||||
img.style = `max-width:95%;max-height:95%;box-shadow:0 0 30px rgba(0,0,0,0.5);border-radius:4px;`
|
||||
overlay.onclick = () => document.body.removeChild(overlay)
|
||||
overlay.appendChild(img)
|
||||
document.body.appendChild(overlay)
|
||||
}
|
||||
const handleUpload = (file) => {
|
||||
if (!file) return
|
||||
const reader = new FileReader()
|
||||
reader.onload = (re) => {
|
||||
if (file.type.startsWith('image/')) {
|
||||
const imgHtml = `<div style="display:inline-block; resize:both; overflow:hidden; vertical-align:bottom; line-height:0; width:200px; height:auto; border:1px dashed #ccc; padding:2px; cursor:pointer;" class="resizable-img-container"><img src="${re.target.result}" style="width:100%; height:100%; object-fit:contain; pointer-events:none;"></div> `
|
||||
exec("insertHTML", imgHtml)
|
||||
} else {
|
||||
const linkHtml = `<a href="${re.target.result}" download="${file.name}" contenteditable="false" style="display:inline-flex; align-items:center; gap:5px; padding:4px 8px; border:1px solid #ccc; border-radius:4px; background:#f9f9f9; text-decoration:none; color:#333; font-size:12px; margin:2px; cursor:pointer;"><span class="icon-[lucide--paperclip] w-3 h-3"></span>${file.name}</a> `
|
||||
exec("insertHTML", linkHtml)
|
||||
}
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
const queryState = (cmd, val = null) => {
|
||||
refreshTick(); if (!editorRef || isSource()) return false
|
||||
try {
|
||||
if (cmd === 'formatBlock') {
|
||||
let node = window.getSelection().getRangeAt(0).commonAncestorContainer
|
||||
while (node && node !== editorRef) {
|
||||
if (node.nodeType === 1 && node.tagName === val) return true
|
||||
node = node.parentNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
return document.queryCommandState(cmd)
|
||||
} catch (e) { return false }
|
||||
}
|
||||
const toolbar = h("div", { class: "flex flex-wrap items-center gap-1 p-2 border-b border-base-300 bg-base-200 sticky top-0 z-20" }, [
|
||||
h("div", { class: "flex flex-wrap gap-1 flex-1 items-center" }, [
|
||||
|
||||
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState('bold') ? 'btn-active bg-primary/20' : ''}`, onclick: () => exec("bold") }, h("span", { class: "icon-[lucide--bold]" })),
|
||||
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState('italic') ? 'btn-active bg-primary/20' : ''}`, onclick: () => exec("italic") }, h("span", { class: "icon-[lucide--italic]" })),
|
||||
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState('underline') ? 'btn-active bg-primary/20' : ''}`, onclick: () => exec("underline") }, h("span", { class: "icon-[lucide--underline]" })),
|
||||
h("input", { type: "color", class: "w-5 h-5 p-0 border-0 bg-transparent cursor-pointer", oninput: (e) => exec("foreColor", e.target.value) }),
|
||||
|
||||
h("span", { class: "w-px h-5 bg-base-300 mx-1" }),
|
||||
|
||||
h("button", {
|
||||
type: "button",
|
||||
class: "btn btn-ghost btn-xs",
|
||||
onclick: () => exec("justifyLeft")
|
||||
}, h("span", { class: "icon-[lucide--align-left]" })),
|
||||
|
||||
h("button", {
|
||||
type: "button",
|
||||
class: "btn btn-ghost btn-xs",
|
||||
onclick: () => exec("justifyCenter")
|
||||
}, h("span", { class: "icon-[lucide--align-center]" })),
|
||||
|
||||
h("button", {
|
||||
type: "button",
|
||||
class: "btn btn-ghost btn-xs",
|
||||
onclick: () => exec("justifyRight")
|
||||
}, h("span", { class: "icon-[lucide--align-right]" })),
|
||||
|
||||
h("span", { class: "w-px h-5 bg-base-300 mx-1" }),
|
||||
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("insertUnorderedList") }, h("span", { class: "icon-[lucide--list]" })),
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("insertOrderedList") }, h("span", { class: "icon-[lucide--list-ordered]" })),
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("outdent") }, h("span", { class: "icon-[lucide--indent-decrease]" })),
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("indent") }, h("span", { class: "icon-[lucide--indent-increase]" })),
|
||||
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState('formatBlock', 'BLOCKQUOTE') ? 'btn-active' : ''}`, onclick: () => exec("formatBlock", queryState('formatBlock', 'BLOCKQUOTE') ? 'P' : 'BLOCKQUOTE') }, h("span", { class: "icon-[lucide--quote]" })),
|
||||
|
||||
h("span", { class: "w-px h-5 bg-base-300 mx-1" }),
|
||||
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => { const url = window.prompt('URL:'); if (url) exec("createLink", url) } }, h("span", { class: "icon-[lucide--link]" })),
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => { const input = document.createElement('input'); input.type = 'file'; input.onchange = (e) => handleUpload(e.target.files[0]); input.click(); } }, h("span", { class: "icon-[lucide--paperclip]" })),
|
||||
|
||||
h("div", { class: "relative" }, [
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: (e) => { e.stopPropagation(); saveSelection(); showEmojis(!showEmojis()); } }, h("span", { class: "icon-[lucide--smile]" })),
|
||||
h("div", { class: "absolute top-full left-0 mt-1 p-2 bg-base-100 border border-base-300 shadow-xl rounded-box w-52 z-50 flex flex-wrap gap-1", style: () => showEmojis() ? "display:flex" : "display:none" }, emojis.map(emo => h("span", { class: "cursor-pointer hover:bg-base-200 p-1 rounded text-lg", onclick: (e) => { e.stopPropagation(); exec("insertText", emo); showEmojis(false); } }, emo)))
|
||||
]),
|
||||
|
||||
h("span", { class: "w-px h-5 bg-base-300 mx-1" }),
|
||||
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("undo") }, h("span", { class: "icon-[lucide--undo-2]" })),
|
||||
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("redo") }, h("span", { class: "icon-[lucide--redo-2]" })),
|
||||
]),
|
||||
|
||||
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${isSource() ? 'btn-active' : ''}`, onclick: () => { if (!isSource()) source(editorRef?.innerHTML || ""); else if (editorRef) { editorRef.innerHTML = source(); notify(); }; isSource(!isSource()) } }, h("span", { class: "icon-[lucide--code-2]" }))
|
||||
])
|
||||
if (typeof document !== 'undefined' && !document.getElementById('editor-styles')) {
|
||||
const style = document.createElement('style')
|
||||
style.id = 'editor-styles'
|
||||
style.textContent = `
|
||||
[contenteditable="true"] div,
|
||||
[contenteditable="true"] p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
return h("div", { class: cls("border border-base-300 rounded-box bg-base-100 overflow-hidden shadow-sm flex flex-col", extraClass) }, [
|
||||
toolbar,
|
||||
h("div", { class: "relative flex-1 flex flex-col", onclick: () => showEmojis(false) }, [
|
||||
h("div", {
|
||||
ref: el => {
|
||||
if (!editorRef && el) {
|
||||
editorRef = el; el.innerHTML = val(value) || "";
|
||||
document.execCommand("defaultParagraphSeparator", false, "br");
|
||||
el.addEventListener('click', (e) => {
|
||||
const container = e.target.closest('.resizable-img-container');
|
||||
if (container) { const img = container.querySelector('img'); if (img) openLightbox(img.src); }
|
||||
});
|
||||
}
|
||||
},
|
||||
style: () => `min-height:22rem;${isSource() ? 'display:none' : ''}`,
|
||||
class: "p-4 outline-none text-base-content leading-relaxed [&>div]:m-0 [&>p]:m-0 [&>div]:min-h-[1em] [&_.resizable-img-container]:hover:border-primary [&_blockquote]:border-l-4 [&_blockquote]:border-base-300 [&_blockquote]:pl-4 [&_blockquote]:italic [&_ul]:list-disc [&_ul]:pl-8 [&_ol]:list-decimal [&_ol]:pl-8",
|
||||
contenteditable: "true",
|
||||
oninput: notify,
|
||||
onkeydown: (e) => { if (e.key === 'Tab') { e.preventDefault(); exec("indent"); } },
|
||||
onkeyup: () => { triggerRefresh(); saveSelection(); },
|
||||
onclick: (e) => { triggerRefresh(); saveSelection(); e.stopPropagation(); },
|
||||
onmouseup: () => { notify(); saveSelection(); },
|
||||
onpaste: (e) => {
|
||||
e.preventDefault();
|
||||
const text = e.clipboardData.getData('text/plain');
|
||||
exec('insertText', text);
|
||||
},
|
||||
ondragover: (e) => e.preventDefault(),
|
||||
ondrop: (e) => { e.preventDefault(); handleUpload(e.dataTransfer.files[0]) }
|
||||
}),
|
||||
h("textarea", {
|
||||
class: "w-full flex-1 min-h-[22rem] p-4 outline-none font-mono text-sm bg-base-200 border-0",
|
||||
style: () => isSource() ? '' : 'display:none',
|
||||
value: source,
|
||||
oninput: (e) => { source(e.target.value); if (editorRef) editorRef.innerHTML = e.target.value; p.onchange?.(e.target.value); }
|
||||
})
|
||||
]),
|
||||
h("div", { class: "px-3 py-1 border-t border-base-300 bg-base-100/50 text-[10px] text-right text-base-content/60 italic" }, [
|
||||
h("span", () => `${count()}`)
|
||||
])
|
||||
])
|
||||
};
|
||||
@@ -94,6 +94,7 @@
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* Solo para la Demo de docsify */
|
||||
.markdown-section progress.progress {
|
||||
all: revert-layer;
|
||||
}
|
||||
|
||||
722
src/sigpro-ui.js
722
src/sigpro-ui.js
@@ -1,527 +1,219 @@
|
||||
import { $, watch, h, mount, when, each, isFunc } from "sigpro"
|
||||
export const val = val => typeof val === "function" ? val() : val;
|
||||
import { $, h, mount, val, isFunc } from "sigpro"
|
||||
|
||||
export const getBy = (item, field = 'label') => (item && typeof item === 'object') ? item[field] : item;
|
||||
export const cls = (...classes) => classes.filter(Boolean).join(' ').trim();
|
||||
export const filterBy = (items, query, field = 'label') => {
|
||||
const q = String(val(query) || '').toLowerCase();
|
||||
const list = (val(items) || []).map(i => typeof i === 'object' ? i : { label: i, value: i });
|
||||
return !q ? list : list.filter(item => String(item[field] || '').toLowerCase().includes(q));
|
||||
};
|
||||
export const rand = (r) => `${r}-${Math.random().toString(36).slice(2, 9)}`
|
||||
export const hide = () => document.activeElement?.blur()
|
||||
const c1 = (tag, cls) => (p) => h(tag, { ...p, class: `${cls} ${p?.class || ''}`.trim() })
|
||||
const c2 = (tag, cls) => (p, c) => h(tag, { ...p, class: `${cls} ${p?.class || ''}`.trim() }, c)
|
||||
const ct = (tag, cls, type) => (p) => h(tag, { type, ...p, class: `${cls} ${p?.class || ''}`.trim() })
|
||||
export const Alert = c2("div", "alert")
|
||||
|
||||
export const Accordion = (p, c) => h('div', { ...p, class: `${'collapse'} ${p?.class || ''}`.trim() }, c)
|
||||
export const AccordionRadio = (p) => h('input', { type: 'radio', name: p.name, checked: p.checked || undefined, class: p.class })
|
||||
export const AccordionTitle = (p, c) => h('div', { ...p, class: `${'collapse-title'} ${p?.class || ''}`.trim() }, c)
|
||||
export const AccordionContent = (p, c) => h('div', { ...p, class: `${'collapse-content'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Alert = (p, c) => h('div', { ...p, class: `${'alert'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Avatar = (p, c) => h("div", { class: "avatar" }, h('div', { class: p.class }, c))
|
||||
export const AvatarGroup = c2("div", "avatar-group -space-x-6")
|
||||
export const Badge = c2("span", "badge")
|
||||
export const Breadcrumbs = c2("div", "breadcrumbs")
|
||||
export const Button = c2("button", "btn")
|
||||
export const Card = c2("div", "card")
|
||||
export const CardTitle = c2("div", "card-title")
|
||||
export const CardBody = c2("div", "card-body")
|
||||
export const CardActions = c2("div", "card-actions")
|
||||
export const Carousel = c2("div", "carousel")
|
||||
export const CarouselItem = c2("div", "carousel-item")
|
||||
export const Chat = c2("div", "chat")
|
||||
export const ChatBubble = c2("div", "chat-bubble")
|
||||
export const ChatFooter = c2("div", "chat-footer")
|
||||
export const ChatHeader = c2("div", "chat-header")
|
||||
export const ChatImage = (p, c) => h("div", { ...p, class: cls("chat-image avatar", p.class) }, h("div", { class: "w-10 rounded-full" }, typeof c === "string" ? h("img", { src: c, alt: "avatar" }) : c))
|
||||
export const Checkbox = ct("input", "checkbox", "checkbox")
|
||||
export const Drawer = c2("div", "drawer")
|
||||
export const DrawerToggle = (p) => input({ ...p, type: 'checkbox', class: 'drawer-toggle', checked: () => val(p.checked), onchange: (e) => isFunc(p.checked) && p.checked(e.target.checked) })
|
||||
export const DrawerContent = c2("div", "drawer-content")
|
||||
export const DrawerSide = c2("div", "drawer-side")
|
||||
export const DrawerOverlay = (p) => label({ ...p, for: p.for, class: cls('drawer-overlay', p.class) })
|
||||
export const Divider = c1("div", "divider")
|
||||
export const Dropdown = c2("div", "dropdown")
|
||||
export const DropdownButton = (p, c) => (h('div', { ...p, tabindex: '0', role: 'button', class: cls('btn', p.class) }, c))
|
||||
export const DropdownContent = (p, c) => (h('div', { ...p, tabindex: '0', class: cls('dropdown-content', p.class) }, c))
|
||||
export const Fab = (p, c) => h("div", { class: "fab" }, [h('div', { tabindex: "0", role: "button", class: cls('btn', p.class) }, Icon({},p.icon)), c])
|
||||
export const Fieldset = (p, c) => h("fieldset", { class: cls("fieldset", p.class) }, [h("legend", { class: "fieldset-legend" }, p.label), c])
|
||||
export const Icon = (p, c) => h("span", { ...p, class: cls(c, p.class) })
|
||||
export const Indicator = (p, c) => h("div", { ...p, class: cls("indicator", p.class) }, [p.value && h("span", { class: cls("indicator-item badge", p.class) }, p.value), c])
|
||||
export const Kbd = c2("kbd", "kbd")
|
||||
export const List = c2("ul", "list")
|
||||
export const ListRows = (p) => () => (val(p.items) || []).map((item, idx) => h('li', { class: cls('list-row', p.class, item?.class) }, typeof p.render === 'function' ? p.render(item, idx) : item))
|
||||
export const Loading = c2("span", "loading loading-spinner")
|
||||
export const Navbar = c2("div", "navbar")
|
||||
export const Progress = c1("progress", "progress")
|
||||
export const Radial = (p, c) => h("div", { class: cls("radial-progress", p.class), style: `--value:${val(p.value) ?? 0};`, role: "progressbar", "aria-valuenow": p.value }, c)
|
||||
export const Radio = ct("input", "radio", "radio")
|
||||
export const Range = ct("input", "range", "range")
|
||||
export const Rating = c2("div", "rating")
|
||||
export const RatingItems = (p) => [...Array(p.count)].map((_, i) => h('input', { class: cls('mask', p.class), name: p.name, type: 'radio', checked: () => val(p.value) === i, onchange: () => isFunc(p.value) ? p.value(i) : p.onchange?.(i) }))
|
||||
export const Skeleton = c1("div", "skeleton")
|
||||
export const SkeletonText = c1("span", "skeleton skeleton-text")
|
||||
export const Stack = c2("div", "stack")
|
||||
export const Stats = c2("div", "stats shadow")
|
||||
export const Steps = c2("ul", "steps")
|
||||
export const Step = (p, c) => h("li", { ...p, class: cls("step", p.class), "data-content": p.dataContent }, c)
|
||||
export const Swap = c2("label", "swap")
|
||||
export const SwapToggle = (p) => h('input', { type: 'checkbox', checked: () => val(p.value), onchange: (e) => isFunc(p.value) && p.value(e.target.checked), class: p.class })
|
||||
export const SwapOn = c2("div", "swap-on")
|
||||
export const SwapOff = c2("div", "swap-off")
|
||||
export const Table = c2("table", "table")
|
||||
export const Textarea = c1("textarea", "textarea")
|
||||
export const Textrotate = (p, c) => h('span', { ...p, class: cls('text-rotate', p.class) }, h('span', {}, c))
|
||||
export const Timeline = c2("ul", "timeline")
|
||||
export const Toggle = ct("input", "toggle", "checkbox")
|
||||
export const Tooltip = (p, c) => h("div", { ...p, class: cls("tooltip", p.class), "data-tip": p.tip }, c)
|
||||
export const Accordion = (p) => {
|
||||
const name = p.name || rand('acc')
|
||||
return each(p.items, (it) => {
|
||||
return h('div', { class: cls('collapse', p.class) }, [
|
||||
h('input', { type: 'radio', name, checked: it.open || undefined }),
|
||||
it.title ? h('div', { class: cls("collapse-title", `${it.classTitle ?? ' font-semibold'}`) }, it.title) : null,
|
||||
it.content ? h('div', { class: cls("collapse-content text-sm", `${it.classContent ?? ' font-semibold'}`) }, it.content) : null,
|
||||
]);
|
||||
});
|
||||
};
|
||||
export const Autocomplete = ({ items, value, onselect, placeholder = '...', ...props }) => {
|
||||
const query = $(val(value) || '')
|
||||
const filtered = $(() => filterBy(items, query()))
|
||||
const pick = (item) => {
|
||||
const display = getBy(item)
|
||||
const actual = typeof item === 'string' ? item : item.value
|
||||
query(display)
|
||||
if (isFunc(value)) value(actual)
|
||||
onselect?.(item)
|
||||
hide()
|
||||
}
|
||||
return Dropdown({ class: 'w-80' }, [
|
||||
h('div', { tabindex: '0', role: 'button', class: 'w-full' }, Input({ ...props, placeholder, value: query, left: Icon({},'icon-[lucide--search]') })),
|
||||
DropdownContent({ class: 'p-2 bg-base-100 rounded-box shadow-xl w-full max-h-60 overflow-y-auto border border-base-300 z-50' },
|
||||
h('ul', { class: 'menu flex-col flex-nowrap w-full p-0' }, [
|
||||
each(filtered, (item) => h('li', {}, [h('a', { onmousedown: (e) => e.preventDefault(), onclick: () => pick(item) }, getBy(item))]), 'value'),
|
||||
() => filtered().length === 0 ? h('li', { class: 'p-4 opacity-50 text-center' }, 'Sin resultados') : null
|
||||
])
|
||||
)
|
||||
])
|
||||
};
|
||||
export const Calendar = (p) => {
|
||||
const internalDate = $(new Date())
|
||||
const hoverDate = $(null)
|
||||
const startHour = $(0)
|
||||
const endHour = $(0)
|
||||
const now = new Date()
|
||||
const todayStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
|
||||
const fmt = d => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
|
||||
const rangeMode = () => val(p.range) === true
|
||||
const current = () => val(p.value)
|
||||
const selectDate = (date) => {
|
||||
const s = fmt(date)
|
||||
const v = current()
|
||||
if (rangeMode()) {
|
||||
if (!v?.start || (v.start && v.end)) {
|
||||
p.onChange?.({ start: s, end: null, ...(p.hour && { startHour: startHour() }) })
|
||||
} else {
|
||||
const start = v.start
|
||||
const nv = s < start ? { start: s, end: start } : { start, end: s }
|
||||
if (p.hour) { nv.startHour = v.startHour ?? startHour(); nv.endHour = endHour() }
|
||||
p.onChange?.(nv)
|
||||
}
|
||||
} else {
|
||||
p.onChange?.(p.hour ? `${s}T${String(startHour()).padStart(2, '0')}:00:00` : s)
|
||||
}
|
||||
}
|
||||
const move = (m) => { const d = internalDate(); internalDate(new Date(d.getFullYear(), d.getMonth() + m, 1)) }
|
||||
const moveYear = (y) => { const d = internalDate(); internalDate(new Date(d.getFullYear() + y, d.getMonth(), 1)) }
|
||||
const HourSlider = ({ value: hVal, onChange: onH }) => h('div', { class: 'flex-1' }, [
|
||||
h('div', { class: 'flex gap-2 items-center' }, [
|
||||
h('input', { type: 'range', min: 0, max: 23, value: hVal, class: 'range range-xs flex-1', oninput: e => onH(+e.target.value) }),
|
||||
h('span', { class: 'text-sm font-mono min-w-[48px] text-center' }, () => String(val(hVal)).padStart(2, '0') + ':00')
|
||||
])
|
||||
])
|
||||
return h('div', {
|
||||
class: cls('p-4 bg-base-100 border border-base-300 shadow-2xl rounded-box w-80 select-none', p.class)
|
||||
}, [
|
||||
h('div', { class: 'flex justify-between items-center mb-4 gap-1' }, [
|
||||
h('div', { class: 'flex gap-0.5' }, [
|
||||
h('button', { type: 'button', class: 'btn btn-ghost btn-xs px-1', onclick: () => moveYear(-1) }, h('span', { class: 'icon-[lucide--chevrons-left]' })),
|
||||
h('button', { type: 'button', class: 'btn btn-ghost btn-xs px-1', onclick: () => move(-1) }, h('span', { class: 'icon-[lucide--chevron-left]' }))
|
||||
]),
|
||||
h('span', { class: 'font-bold uppercase flex-1 text-center' }, () => internalDate().toLocaleString('es-ES', { month: 'short', year: 'numeric' })),
|
||||
h('div', { class: 'flex gap-0.5' }, [
|
||||
h('button', { type: 'button', class: 'btn btn-ghost btn-xs px-1', onclick: () => move(1) }, h('span', { class: 'icon-[lucide--chevron-right]' })),
|
||||
h('button', { type: 'button', class: 'btn btn-ghost btn-xs px-1', onclick: () => moveYear(1) }, h('span', { class: 'icon-[lucide--chevrons-right]' }))
|
||||
])
|
||||
]),
|
||||
h('div', { class: 'grid grid-cols-7 gap-1', onmouseleave: () => hoverDate(null) }, [
|
||||
...['L', 'M', 'X', 'J', 'V', 'S', 'D'].map(d => h('div', { class: 'text-[10px] opacity-40 font-bold text-center' }, d)),
|
||||
() => {
|
||||
const d = internalDate(), y = d.getFullYear(), m = d.getMonth()
|
||||
const firstDay = new Date(y, m, 1).getDay()
|
||||
const offset = firstDay === 0 ? 6 : firstDay - 1
|
||||
const dim = new Date(y, m + 1, 0).getDate()
|
||||
const cells = []
|
||||
for (let i = 0; i < offset; i++) cells.push(h('div'))
|
||||
for (let i = 1; i <= dim; i++) {
|
||||
const date = new Date(y, m, i), ds = fmt(date)
|
||||
cells.push(h('button', {
|
||||
type: 'button',
|
||||
class: () => {
|
||||
const v = current(), h = hoverDate()
|
||||
const isStart = typeof v === 'string' ? v.split('T')[0] === ds : v?.start === ds
|
||||
const isEnd = v?.end === ds
|
||||
let inRange = false
|
||||
if (rangeMode() && v?.start) {
|
||||
const start = v.start
|
||||
if (!v.end && h) inRange = (ds > start && ds <= h) || (ds < start && ds >= h)
|
||||
else if (v.end) inRange = ds > start && ds < v.end
|
||||
}
|
||||
const base = 'btn btn-xs p-0 aspect-square min-h-0 h-auto font-normal relative'
|
||||
const st = isStart || isEnd ? 'btn-primary z-10' : inRange ? 'bg-primary/20 border-none rounded-none' : 'btn-ghost'
|
||||
const today = ds === todayStr ? 'ring-1 ring-primary ring-inset font-black text-primary' : ''
|
||||
return cls(base, st, today)
|
||||
},
|
||||
onmouseenter: () => rangeMode() && hoverDate(ds),
|
||||
onclick: () => selectDate(date)
|
||||
}, i.toString()))
|
||||
}
|
||||
return cells
|
||||
}
|
||||
]),
|
||||
p.hour ? h('div', { class: 'mt-3 pt-2 border-t border-base-300' },
|
||||
rangeMode()
|
||||
? h('div', { class: 'flex gap-4' }, [HourSlider({ value: startHour, onChange: h => startHour(h) }), HourSlider({ value: endHour, onChange: h => endHour(h) })])
|
||||
: HourSlider({ value: startHour, onChange: h => startHour(h) })
|
||||
) : null
|
||||
])
|
||||
};
|
||||
export const Colorpicker = (p) => {
|
||||
const current = () => val(p.value) || '#000000'
|
||||
return Dropdown({}, [
|
||||
DropdownButton({ class: 'btn' }, [
|
||||
h('div', { class: 'size-5 rounded-sm', style: () => `background-color: ${current()}` }),
|
||||
p.label && h('span', {}, p.label)
|
||||
]),
|
||||
DropdownContent({ class: 'p-0' },
|
||||
ColorPalette({ value: p.value, onchange: (c) => { isFunc(p.value) ? p.value(c) : p.onchange?.(c) } })
|
||||
)
|
||||
])
|
||||
};
|
||||
export const ColorPalette = (p) => {
|
||||
const current = () => val(p.value) || '#000000'
|
||||
const palette = [
|
||||
'#000', '#1A1A1A', '#333', '#4D4D4D', '#666', '#808080', '#B3B3B3', '#FFF',
|
||||
'#450a0a', '#7f1d1d', '#991b1b', '#b91c1c', '#dc2626', '#ef4444', '#f87171', '#fca5a5',
|
||||
'#431407', '#7c2d12', '#9a3412', '#c2410c', '#ea580c', '#f97316', '#fb923c', '#ffedd5',
|
||||
'#713f12', '#a16207', '#ca8a04', '#eab308', '#facc15', '#fde047', '#fef08a', '#fff9c4',
|
||||
'#064e3b', '#065f46', '#059669', '#10b981', '#34d399', '#4ade80', '#84cc16', '#d9f99d',
|
||||
'#082f49', '#075985', '#0284c7', '#0ea5e9', '#38bdf8', '#7dd3fc', '#22d3ee', '#cffafe',
|
||||
'#1e1b4b', '#312e81', '#4338ca', '#4f46e5', '#6366f1', '#818cf8', '#a5b4fc', '#e0e7ff',
|
||||
'#2e1065', '#4c1d95', '#6d28d9', '#7c3aed', '#8b5cf6', '#a855f7', '#d946ef', '#fae8ff'
|
||||
]
|
||||
const pick = (c) => {
|
||||
isFunc(p.value) ? p.value(c) : p.onchange?.(c)
|
||||
hide()
|
||||
}
|
||||
export const AvatarGroup = (p, c) => h('div', { ...p, class: `${'avatar-group -space-x-6'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Badge = (p, c) => h('span', { ...p, class: `${'badge'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Breadcrumbs = (p, c) => h('div', { ...p, class: `${'breadcrumbs'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Button = (p, c) => h('button', { ...p, class: `${'btn'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Calendar = p => {
|
||||
let [d, hv, sh, eh] = [$(new Date()), $(0), $(0), $(0)], now = new Date(),
|
||||
F = v => v?.toISOString().slice(0, 10),
|
||||
P = n => (n < 10 ? '0' : '') + n,
|
||||
M = (m, y = 0) => d(new Date(d().getFullYear() + y, d().getMonth() + m, 1)),
|
||||
V = () => typeof p.value == 'function' ? p.value() : p.value,
|
||||
G = () => typeof p.range == 'function' ? p.range() : p.range,
|
||||
L = dt => {
|
||||
let s = F(dt), v = V(), r = G();
|
||||
if (!r) return p.onChange?.(p.hour ? `${s}T${P(sh())}:00:00` : s);
|
||||
if (!v?.start || v.end) return p.onChange?.({ start: s, end: null, ...(p.hour && { startHour: sh() }) });
|
||||
let nv = s < v.start ? { start: s, end: v.start } : { start: v.start, end: s };
|
||||
p.onChange?.({ ...nv, ...(p.hour && { startHour: v.startHour ?? sh(), endHour: eh() }) });
|
||||
},
|
||||
I = ({ v, on }) => h('div', { class: 'flex-1 flex gap-2 items-center' }, [
|
||||
h('input', { type: 'range', min: 0, max: 23, value: v, class: 'range range-xs', oninput: e => on(+e.target.value) }),
|
||||
h('span', { class: 'text-sm font-mono' }, () => P(v()) + ':00')
|
||||
]);
|
||||
|
||||
return h('div', {
|
||||
class: cls('p-3 bg-base-100 rounded-box shadow w-64', p.class)
|
||||
}, h('div', { class: 'grid grid-cols-8 gap-1' },
|
||||
palette.map(c => h('button', {
|
||||
type: 'button',
|
||||
style: `background-color: ${c}`,
|
||||
return h('div', { class: `p-4 bg-base-100 border shadow-2xl rounded-box w-80 select-none ${p.class || ''}` }, [
|
||||
h('div', { class: 'flex justify-between items-center mb-4' }, [
|
||||
h('div', { class: 'flex' }, [['-1y', -1, 1], ['-1m', -1, 0]].map(([_, m, y]) => h('button', { class: 'btn btn-ghost btn-xs', onclick: () => M(m, y) }, h('span', { class: `icon-[lucide--chevron${y ? 's' : ''}-left]` })))),
|
||||
h('span', { class: 'font-bold uppercase' }, () => d().toLocaleString('es', { month: 'short', year: 'numeric' })),
|
||||
h('div', { class: 'flex' }, [[1, 0], [1, 1]].map(([m, y]) => h('button', { class: 'btn btn-ghost btn-xs', onclick: () => M(m, y) }, h('span', { class: `icon-[lucide--chevron${y ? 's' : ''}-right]` }))))
|
||||
]),
|
||||
h('div', { class: 'grid grid-cols-7 gap-1', onmouseleave: () => hv(null) }, [
|
||||
...'LMXJVSD'.split('').map(l => h('div', { class: 'text-[10px] opacity-40 font-bold text-center' }, l)),
|
||||
() => {
|
||||
let y = d().getFullYear(), m = d().getMonth(), first = (new Date(y, m, 1).getDay() + 6) % 7;
|
||||
return [...Array(first).fill(h('div')), ...Array(new Date(y, m + 1, 0).getDate()).keys()].map(i => {
|
||||
if (typeof i != 'number') return i;
|
||||
let day = i + 1, ds = F(new Date(y, m, day)), today = F(now) == ds;
|
||||
return h('button', {
|
||||
type: 'button', onclick: () => L(new Date(y, m, day)), onmouseenter: () => G() && hv(ds),
|
||||
class: () => {
|
||||
const act = current().toLowerCase() === c.toLowerCase()
|
||||
return `size-6 rounded-sm cursor-pointer transition-all hover:scale-125 hover:z-10 active:scale-95 outline-none border border-black/5 p-0 min-h-0 ${act ? 'ring-2 ring-offset-1 ring-primary z-10 scale-110' : ''}`
|
||||
},
|
||||
onclick: () => { pick(c) }
|
||||
}))
|
||||
))
|
||||
};
|
||||
export const Datepicker = (p) => {
|
||||
const displayValue = $("")
|
||||
const rangeMode = () => val(p.range) === true
|
||||
|
||||
watch(() => {
|
||||
const v = val(p.value)
|
||||
if (!v) return displayValue("")
|
||||
let text = ""
|
||||
if (typeof v === "string") {
|
||||
text = p.hour && v.includes("T") ? v.replace("T", " ") : v
|
||||
} else if (v.start && v.end) {
|
||||
const startStr = p.hour && v.startHour != null ? `${v.start} ${String(v.startHour).padStart(2, "0")}:00` : v.start
|
||||
const endStr = p.hour && v.endHour != null ? `${v.end} ${String(v.endHour).padStart(2, "0")}:00` : v.end
|
||||
text = `${startStr} - ${endStr}`
|
||||
} else if (v.start) {
|
||||
const startStr = p.hour && v.startHour != null ? `${v.start} ${String(v.startHour).padStart(2, "0")}:00` : v.start
|
||||
text = `${startStr}...`
|
||||
}
|
||||
displayValue(text)
|
||||
})
|
||||
|
||||
const handleChange = (val) => {
|
||||
if (isFunc(p.value)) p.value(val)
|
||||
else p.onChange?.(val)
|
||||
if (!rangeMode() || val?.end != null) hide()
|
||||
}
|
||||
|
||||
return Dropdown({ class: cls('w-full', p.class) }, [
|
||||
h('label', {
|
||||
tabindex: '0',
|
||||
role: 'button',
|
||||
class: 'input input-bordered flex items-center gap-2 cursor-pointer'
|
||||
}, [
|
||||
h('span', { class: 'icon-[lucide--calendar] shrink-0' }),
|
||||
h('span', {
|
||||
class: () => `grow text-left truncate ${!displayValue() ? 'opacity-50' : ''}`,
|
||||
}, () => displayValue() || p.placeholder || (rangeMode() ? 'Seleccionar rango...' : 'Seleccionar fecha...')),
|
||||
() => displayValue() ? h('button', {
|
||||
type: 'button',
|
||||
class: 'btn btn-ghost btn-xs btn-circle -mr-2',
|
||||
onmousedown: (e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
if (isFunc(p.value)) p.value(null)
|
||||
else p.onChange?.(null)
|
||||
displayValue("") // Forzar limpieza visual inmediata
|
||||
}
|
||||
}, h('span', { class: 'icon-[lucide--x] opacity-50' })) : null
|
||||
]),
|
||||
DropdownContent({ class: 'p-0' },
|
||||
Calendar({ value: p.value, range: rangeMode(), hour: p.hour, onChange: handleChange })
|
||||
)
|
||||
])
|
||||
};
|
||||
export const Fileinput = (p) => {
|
||||
const files = $([])
|
||||
const drag = $(false)
|
||||
const error = $(null)
|
||||
const maxBytes = (p.max || 2) * 1024 * 1024
|
||||
const process = (fileList) => {
|
||||
const arr = Array.from(fileList)
|
||||
error(null)
|
||||
if (arr.some(f => f.size > maxBytes)) {
|
||||
error(`Máx ${p.max || 2}MB`)
|
||||
return
|
||||
}
|
||||
const updated = [...files(), ...arr]
|
||||
files(updated)
|
||||
if (isFunc(p.onselect)) p.onselect(updated)
|
||||
else if (isFunc(p.value)) p.value(updated)
|
||||
}
|
||||
const remove = (idx) => {
|
||||
const updated = files().filter((_, i) => i !== idx)
|
||||
files(updated)
|
||||
if (isFunc(p.onselect)) p.onselect(updated)
|
||||
else if (isFunc(p.value)) p.value(updated)
|
||||
}
|
||||
return h('div', { class: cls('fieldset w-full p-0', p.class) }, [
|
||||
h('label', {
|
||||
class: () => `relative flex items-center justify-between w-full h-12 px-4 border-2 border-dashed rounded-lg cursor-pointer transition-all duration-200 ${drag() ? 'border-primary bg-primary/10' : 'border-base-content/20 bg-base-100 hover:bg-base-200'}`,
|
||||
ondragover: (e) => { e.preventDefault(); drag(true) },
|
||||
ondragleave: () => drag(false),
|
||||
ondrop: (e) => { e.preventDefault(); drag(false); process(e.dataTransfer.files) }
|
||||
}, [
|
||||
h('div', { class: 'flex items-center gap-3 w-full' }, [
|
||||
h('span', { class: 'icon-[lucide--upload]' }),
|
||||
h('span', { class: 'text-sm opacity-70 truncate grow text-left' }, '...'),
|
||||
h('span', { class: 'text-[10px] opacity-40 shrink-0' }, `Máx ${p.max || 2}MB`)
|
||||
]),
|
||||
h('input', {
|
||||
type: 'file',
|
||||
multiple: true,
|
||||
accept: p.accept || '*',
|
||||
class: 'hidden',
|
||||
onchange: (e) => process(e.target.files)
|
||||
})
|
||||
]),
|
||||
() => error() && h('span', { class: 'text-[10px] text-error mt-1 px-1 font-medium' }, error()),
|
||||
when(() => files().length > 0, () =>
|
||||
h('ul', { class: 'mt-2 space-y-1' },
|
||||
each(files, (file, idx) =>
|
||||
h('li', { class: 'flex items-center justify-between p-1.5 pl-3 text-xs bg-base-200/50 rounded-md border border-base-300' }, [
|
||||
h('div', { class: 'flex items-center gap-2 truncate' }, [
|
||||
h('span', { class: 'opacity-50' }, '📄'),
|
||||
h('span', { class: 'truncate font-medium max-w-[200px]' }, file.name),
|
||||
h('span', { class: 'text-[9px] opacity-40' }, `(${(file.size / 1024).toFixed(0)} KB)`)
|
||||
]),
|
||||
h('button', {
|
||||
type: 'button',
|
||||
class: 'btn btn-ghost btn-xs btn-circle',
|
||||
onclick: (e) => { e.preventDefault(); remove(idx) }
|
||||
}, h('span', { class: 'icon-[lucide--x]' }))
|
||||
])
|
||||
)
|
||||
)
|
||||
)
|
||||
])
|
||||
};
|
||||
export const Input = (p) => {
|
||||
const { label, icon, float, placeholder, value, left, right, rule, hint, content, ...rest } = p;
|
||||
const showPassword = $(false);
|
||||
const isPassword = p.type === 'password';
|
||||
const pattern = rule ?? null;
|
||||
const inputType = () => isPassword ? (val(showPassword) ? 'text' : 'password') : (p.type || 'search');
|
||||
return h("label", { class: float ? 'floating-label' : '' }, [
|
||||
float ? h("span", {}, label) : null,
|
||||
h("label", { pattern: pattern, class: () => cls('input validator', p.class) },
|
||||
[
|
||||
label && !float ? h('span', { class: 'label' }, label) : null,
|
||||
left ?? null,
|
||||
h('input', { ...rest, type: inputType, class: 'grow', pattern: pattern, placeholder: placeholder || label || ' ', value: value }),
|
||||
right ?? null,
|
||||
isPassword ? Swap({ class: 'ml-2' }, [
|
||||
SwapToggle({ value: showPassword, class: "swap-rotate" }),
|
||||
SwapOn({}, Icon({},'icon-[lucide--eye]')),
|
||||
SwapOff({}, Icon({},'icon-[lucide--eye-off]')),
|
||||
]) : null
|
||||
]),
|
||||
hint ? h('div', { class: "validator-hint" }, hint) : null,
|
||||
]);
|
||||
};
|
||||
export const Menu = (p) => {
|
||||
if (p.children !== undefined) return h('ul', { class: cls('menu', p.class), ...p }, p.children)
|
||||
const { items } = p
|
||||
const render = (item) => item.children
|
||||
? h('li', {}, h('details', { open: item.open || undefined }, [
|
||||
h('summary', {}, getBy(item)),
|
||||
h('ul', {}, each(() => val(item.children) || [], render))
|
||||
]))
|
||||
: h('li', {}, h('a', {
|
||||
href: item.href,
|
||||
onclick: item.onclick ? (e) => { if (!item.href) e.preventDefault(); item.onclick(e) } : null
|
||||
}, getBy(item)))
|
||||
return h('ul', { class: cls('menu', p.class) },
|
||||
each(() => val(items) || [], render)
|
||||
)
|
||||
};
|
||||
export const Modal = (p, c) => {
|
||||
let dialogRef = null;
|
||||
watch(() => { const isOpen = val(p.open); if (!dialogRef) return; isOpen ? dialogRef.showModal() : dialogRef.close(); });
|
||||
const close = () => isFunc(p.open) && p.open(false);
|
||||
return h("dialog", { ...p, ref: el => dialogRef = el, class: 'modal', onclose: close, oncancel: close }, [
|
||||
h("div", { class: cls("modal-box", p.class ?? '') }, [
|
||||
p.title && h("h3", { class: "text-lg font-bold" }, p.title),
|
||||
c,
|
||||
h("div", { class: "modal-action" }, [
|
||||
p.actions || Button({ class: 'btn', onclick: close }, 'Cerrar')
|
||||
])
|
||||
]),
|
||||
h("form", { method: "dialog", class: "modal-backdrop" }, [
|
||||
h("button", {}, "close")
|
||||
])
|
||||
]);
|
||||
};
|
||||
export const Select = (p, c) => {
|
||||
if (c !== undefined) return h('select', { class: cls('select', p.class), ...p }, c)
|
||||
const { label, float, placeholder, placeholderDisabled = true, value, left, right, hint, items, keyFn, ...rest } = p
|
||||
const opts = () => {
|
||||
const raw = val(items) || []
|
||||
const ph = placeholder ? [{ disabled: placeholderDisabled, label: placeholder, value: '' }] : []
|
||||
return [...ph, ...raw]
|
||||
}
|
||||
return h('label', { class: float ? 'floating-label' : '' }, [
|
||||
float ? h('span', {}, label) : null,
|
||||
h('label', { class: cls('select', rest.class) }, [
|
||||
(!float && label) ? h('span', { class: 'label' }, label) : null,
|
||||
left ?? null,
|
||||
h('select', {
|
||||
value: () => val(value),
|
||||
onchange: (e) => isFunc(value) ? value(e.target.value) : rest.onchange?.(e)
|
||||
},
|
||||
each(opts, (item) => {
|
||||
const val = getBy(item, item.value !== undefined ? 'value' : undefined)
|
||||
const lab = getBy(item, 'label')
|
||||
return h('option', { value: val, disabled: item.disabled || undefined }, lab)
|
||||
})
|
||||
),
|
||||
right ?? null
|
||||
]),
|
||||
hint ? h('div', { class: 'validator-hint' }, hint) : null
|
||||
])
|
||||
};
|
||||
export const Stat = (p) => h('div', { ...p, class: cls('stat', p.class) }, [
|
||||
p.title ? h('div', { class: 'stat-title' }, p.title) : null,
|
||||
p.value ? h('div', { class: 'stat-value' }, p.value) : null,
|
||||
p.desc ? h('div', { class: 'stat-desc' }, p.desc) : null
|
||||
]);
|
||||
export const TableItems = ({ items, columns = [], header = true }) => {
|
||||
const head = header !== false && columns.some(c => c.label) ? h('thead', {}, h('tr', {}, columns.map(c => h('th', { class: c.class }, c.label)))) : null
|
||||
const body = h('tbody', {}, () => {
|
||||
const list = val(items) || []
|
||||
return list.map((it, idx) => h('tr', {}, columns.map(c => { const v = c.render ? c.render(it, idx) : it[c.key]; return h('td', { class: c.class }, v) })))
|
||||
})
|
||||
return [head, body].filter(Boolean)
|
||||
};
|
||||
export const Tabs = (p, c) => {
|
||||
if (!p.items) {
|
||||
const { class: className, ...rest } = p
|
||||
return h('div', { ...rest, class: cls('tabs', className) }, c)
|
||||
}
|
||||
const { items, activeIndex, onClose, class: className, ...rest } = p
|
||||
const get = x => (isFunc(x) ? x() : x)
|
||||
const closeH = onClose || (isFunc(items) ? (idx, item) => {
|
||||
const arr = val(items)
|
||||
const newArr = arr.filter((_, i) => i !== idx)
|
||||
items(newArr)
|
||||
if (activeIndex() >= newArr.length) activeIndex(Math.max(0, newArr.length - 1))
|
||||
} : null)
|
||||
return h('div', { ...rest, class: cls('tabs', className) }, () => {
|
||||
const list = val(items) || []
|
||||
return list.flatMap((it, idx) => {
|
||||
const isActive = () => activeIndex() === idx
|
||||
const button = h('button', {
|
||||
class: () => `tab ${isActive() ? 'tab-active' : ''} ${it.class || ''}`,
|
||||
onclick: (e) => { e.preventDefault(); activeIndex(idx); it.onclick?.(e) }
|
||||
}, [
|
||||
getBy(it),
|
||||
it.closable ? h('span', {
|
||||
class: 'ml-1 inline-flex items-center justify-center w-4 h-4 rounded-full hover:bg-base-300 text-base-content/60 hover:text-base-content cursor-pointer',
|
||||
onclick: (e) => { e.stopPropagation(); closeH?.(idx, it) }
|
||||
}, h('span', { class: 'icon-[lucide--x] w-3 h-3' })) : null
|
||||
])
|
||||
const contentDiv = h('div', {
|
||||
class: 'tab-content bg-base-100 border-base-300 p-6',
|
||||
style: () => `display: ${isActive() ? 'block' : 'none'};`
|
||||
}, isFunc(it.content) ? it.content() : it.content)
|
||||
return [button, contentDiv]
|
||||
let v = V(), hov = hv(), s = v?.start || (typeof v == 'string' ? v.slice(0, 10) : 0),
|
||||
isE = v?.end == ds, isS = s == ds,
|
||||
inR = G() && v?.start && (v.end ? (ds > v.start && ds < v.end) : (hov && ((ds > s && ds <= hov) || (ds < s && ds >= hov))));
|
||||
return `btn btn-xs p-0 aspect-square min-h-0 h-auto font-normal relative ${isS || isE ? 'btn-primary z-10' : inR ? 'bg-primary/20 border-none rounded-none' : 'btn-ghost'} ${today ? 'ring-1 ring-primary font-black' : ''}`
|
||||
}
|
||||
}, day)
|
||||
})
|
||||
})
|
||||
}
|
||||
]),
|
||||
p.hour && h('div', { class: 'mt-3 pt-2 border-t flex gap-4' }, G() ? [I({ v: sh, on: sh }), I({ v: eh, on: eh })] : [I({ v: sh, on: sh })])
|
||||
])
|
||||
}
|
||||
export const Card = (p, c) => h('div', { ...p, class: `${'card'} ${p?.class || ''}`.trim() }, c)
|
||||
export const CardTitle = (p, c) => h('div', { ...p, class: `${'card-title'} ${p?.class || ''}`.trim() }, c)
|
||||
export const CardBody = (p, c) => h('div', { ...p, class: `${'card-body'} ${p?.class || ''}`.trim() }, c)
|
||||
export const CardActions = (p, c) => h('div', { ...p, class: `${'card-actions'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Carousel = (p, c) => h('div', { ...p, class: `${'carousel'} ${p?.class || ''}`.trim() }, c)
|
||||
export const CarouselItem = (p, c) => h('div', { ...p, class: `${'carousel-item'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Chat = (p, c) => h('div', { ...p, class: `${'chat'} ${p?.class || ''}`.trim() }, c)
|
||||
export const ChatBubble = (p, c) => h('div', { ...p, class: `${'chat-bubble'} ${p?.class || ''}`.trim() }, c)
|
||||
export const ChatFooter = (p, c) => h('div', { ...p, class: `${'chat-footer'} ${p?.class || ''}`.trim() }, c)
|
||||
export const ChatHeader = (p, c) => h('div', { ...p, class: `${'chat-header'} ${p?.class || ''}`.trim() }, c)
|
||||
export const ChatImage = (p, c) => h("div", { ...p, class: `${'chat-image avatar'} ${p?.class || ''}`.trim() }, h("div", { class: "w-10 rounded-full" }, typeof c === "string" ? h("img", { src: c, alt: "avatar" }) : c))
|
||||
export const Checkbox = (p) => h('input', { type: 'checkbox', ...p, class: `${'checkbox'} ${p?.class || ''}`.trim() })
|
||||
export const ColorPalette = p => {
|
||||
let L = s => (s || '').toLowerCase(),
|
||||
C = '#000,#1A1A1A,#333,#4D4D4D,#666,#808080,#B3B3B3,#FFF,#450a0a,#7f1d1d,#991b1b,#b91c1c,#dc2626,#ef4444,#f87171,#fca5a5,#431407,#7c2d12,#9a3412,#c2410c,#ea580c,#f97316,#fb923c,#ffedd5,#713f12,#a16207,#ca8a04,#eab308,#facc15,#fde047,#fef08a,#fff9c4,#064e3b,#065f46,#059669,#10b981,#34d399,#4ade80,#84cc16,#d9f99d,#082f49,#075985,#0284c7,#0ea5e9,#38bdf8,#7dd3fc,#22d3ee,#cffafe,#1e1b4b,#312e81,#4338ca,#4f46e5,#6366f1,#818cf8,#a5b4fc,#e0e7ff,#2e1065,#4c1d95,#6d28d9,#7c3aed,#8b5cf6,#a855f7,#d946ef,#fae8ff'.split(',');
|
||||
|
||||
return h('div', { class: `p-3 bg-base-100 rounded-box shadow w-64 ${p.class || ''}` },
|
||||
h('div', { class: 'grid grid-cols-8 gap-1' }, C.map(c => h('button', {
|
||||
type: 'button',
|
||||
style: { background: c },
|
||||
onclick: () => (isFunc(p.value) ? p.value(c) : p.onchange?.(c), hide()),
|
||||
class: () => `size-6 rounded-sm transition-all hover:scale-125 hover:z-10 active:scale-95 border border-black/5 p-0 min-h-0 ${L(val(p.value)) == L(c) ? 'ring-2 ring-offset-1 ring-primary z-10 scale-110' : ''}`
|
||||
})))
|
||||
);
|
||||
};
|
||||
export const Toast = (message, type = "alert-success", duration = 3500) => {
|
||||
let container = document.getElementById("sigpro-toast-container");
|
||||
if (!container) {
|
||||
container = h("div", { id: "sigpro-toast-container", class: "fixed top-0 right-0 z-[9999] p-4 flex flex-col items-end gap-2 pointer-events-none" });
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
const host = h("div", { style: "display: contents" });
|
||||
container.appendChild(host);
|
||||
let closeFn, timer, enterTimer;
|
||||
const ToastComponent = () => {
|
||||
const visible = $(false);
|
||||
const leaving = $(false);
|
||||
closeFn = () => {
|
||||
if (leaving()) return;
|
||||
clearTimeout(timer);
|
||||
clearTimeout(enterTimer);
|
||||
leaving(true);
|
||||
setTimeout(() => { instance.destroy(); host.remove(); if (!container.hasChildNodes()) container.remove(); }, 300);
|
||||
};
|
||||
enterTimer = setTimeout(() => visible(true), 0);
|
||||
const content = typeof message === 'function' ? val(message) : message;
|
||||
const msgNode = typeof content === 'string' ? h("span", {}, content) : content;
|
||||
return h("div", {
|
||||
class: () => {
|
||||
const base = `alert alert-soft ${type} shadow-lg transition-all duration-300 inline-flex w-auto whitespace-nowrap pointer-events-auto`;
|
||||
if (leaving()) return `${base} translate-x-full opacity-0`;
|
||||
if (visible()) return `${base} translate-x-0 opacity-100`;
|
||||
return `${base} translate-x-10 opacity-0`;
|
||||
}
|
||||
}, [
|
||||
msgNode,
|
||||
h("button", {
|
||||
class: "btn btn-xs btn-circle btn-ghost",
|
||||
onclick: closeFn
|
||||
}, h("span", { class: "icon-[lucide--x]" }))
|
||||
]);
|
||||
};
|
||||
const instance = mount(ToastComponent, host);
|
||||
if (duration > 0) timer = setTimeout(closeFn, duration);
|
||||
return closeFn;
|
||||
};
|
||||
export const Combo = (p, c) => Dropdown({}, [div({ tabindex: '0', role: 'button' }, c), DropdownContent({ class: p?.class }, p.content)])
|
||||
export const Drawer = (p, c) => h('div', { ...p, class: `${'drawer'} ${p?.class || ''}`.trim() }, c)
|
||||
export const DrawerToggle = (p) => input({ ...p, type: 'checkbox', class: 'drawer-toggle', checked: () => val(p.checked), onchange: (e) => isFunc(p.checked) && p.checked(e.target.checked) })
|
||||
export const DrawerContent = (p, c) => h('div', { ...p, class: `${'drawer-content'} ${p?.class || ''}`.trim() }, c)
|
||||
export const DrawerSide = (p, c) => h('div', { ...p, class: `${'drawer-side'} ${p?.class || ''}`.trim() }, c)
|
||||
export const DrawerOverlay = (p) => label({ ...p, for: p.for, class: `${'drawer-overlay'} ${p?.class || ''}`.trim() })
|
||||
export const Divider = (p) => h('div', { ...p, class: `${'divider'} ${p?.class || ''}`.trim() })
|
||||
export const Dropdown = (p, c) => h('div', { ...p, class: `${'dropdown'} ${p?.class || ''}`.trim() }, c)
|
||||
export const DropdownButton = (p, c) => (h('div', { ...p, tabindex: '0', role: 'button', class: `${'btn'} ${p?.class || ''}`.trim() }, c))
|
||||
export const DropdownContent = (p, c) => (h('div', { ...p, tabindex: '0', class: `${'dropdown-content'} ${p?.class || ''}`.trim() }, c))
|
||||
export const Fab = (p, c) => h("div", { class: "fab" }, [h('div', { tabindex: "0", role: "button", class: `${'btn'} ${p?.class || ''}`.trim() }, Icon({}, p.icon)), c])
|
||||
export const Fieldset = (p, c) => h("fieldset", { class: `${'fieldset'} ${p?.class || ''}`.trim() }, [h("legend", { class: "fieldset-legend" }, p.label), c])
|
||||
export const FileDrag = (p, c) => h('label', {
|
||||
class: () => `relative flex items-center justify-between h-12 px-4 border-2 border-dashed rounded-lg cursor-pointer transition-all ${p.drag ? 'border-primary bg-primary/10' : 'border-base-content/20 bg-base-100'} ${p?.class || ''}`,
|
||||
ondragover: (e) => { e.preventDefault(); p.ondrag?.(true) },
|
||||
ondragleave: () => p.ondrag?.(false),
|
||||
ondrop: (e) => { e.preventDefault(); p.ondrag?.(false); p.ondrop?.(e.dataTransfer.files) }
|
||||
}, c)
|
||||
export const FileInput = (p) => h('input', { type: 'file', multiple: true, accept: p.accept || '*', class: `${'file-input'} ${p?.class || ''}`.trim(), onchange: (e) => p.onchange?.(e.target.files) })
|
||||
export const FilePreview = (p) => h('ul', { class: `mt-2 space-y-1 ${p?.class || ''}` },
|
||||
p.files.map((f, i) =>
|
||||
h('li', { class: 'flex items-center justify-between p-1.5 pl-3 text-xs bg-base-200/50 rounded-md border' }, [
|
||||
h('div', { class: 'flex items-center gap-2 truncate opacity-70' }, [
|
||||
h('span', {}, '📄'),
|
||||
h('span', { class: 'truncate max-w-[180px]' }, f.name),
|
||||
h('span', { class: 'text-[9px] opacity-50' }, `(${~~(f.size / 1024)}KB)`)
|
||||
]),
|
||||
h('button', { class: 'btn btn-ghost btn-xs btn-circle', onclick: () => p.onremove?.(i) },
|
||||
h('span', { class: 'icon-[lucide--x]' })
|
||||
)
|
||||
])
|
||||
)
|
||||
)
|
||||
export const FileError = (p) => h('div', { class: `text-[10px] text-error mt-1 px-1 ${p?.class || ''}` }, p.message)
|
||||
export const Filter = (s, i, o, k) => o($(() => val(i).filter(i => String(k ? i[k] : i).toLowerCase().includes(val(s).toLowerCase()))))
|
||||
export const Icon = (p, c) => h("span", { ...p, class: `${c ?? ''} ${p?.class || ''}`.trim() })
|
||||
export const Indicator = (p, c) => h("div", { ...p, class: `${'indicator'} ${p?.class || ''}`.trim() }, [p.value && h("span", { class: `${'indicator-item badge'} ${p?.class || ''}`.trim() }, p.value), c])
|
||||
export const Input = (p) => h('input', { ...p, class: `${'input'} ${p?.class || ''}`.trim() })
|
||||
export const InputPass = (p) => {
|
||||
const show = $(false)
|
||||
return [
|
||||
Input({ ...p, type: show() ? 'text' : 'password' }),
|
||||
Swap({ class: 'ml-2' }, [SwapToggle({ value: show, class: 'swap-rotate' }), SwapOn({}, Icon({}, 'icon-[lucide--eye]')), SwapOff({}, Icon({}, 'icon-[lucide--eye-off]'))])
|
||||
]
|
||||
}
|
||||
export const InputHint = (p, c) => h('div', { ...p, class: `${'validator-hint'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Kbd = (p, c) => h('kbd', { ...p, class: `${'kbd'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Label = (p, c) => h('span', { ...p, class: `${'label'} ${p?.class || ''}`.trim() }, c)
|
||||
export const LabelFloating = (p, c) => h('label', { ...p, class: `${'floating-label'} ${p?.class || ''}`.trim() }, c)
|
||||
export const LabelInput = (p, c) => h('label', { ...p, class: `${'input'} ${p?.class || ''}`.trim() }, c)
|
||||
export const LabelSelect = (p, c) => h('label', { ...p, class: `${'select'} ${p?.class || ''}`.trim() }, c)
|
||||
export const List = (p, c) => h('ul', { ...p, class: `${'list'} ${p?.class || ''}`.trim() }, c)
|
||||
export const ListRows = (p) => () => (val(p.items) || []).map((item, idx) => h('li', { class: `${'list-row'} ${p?.class || ''} ${item?.class || ''}`.trim() }, typeof p.render === 'function' ? p.render(item, idx) : item))
|
||||
export const Menu = (p, c) => ul({ ...p, class: `${'menu'} ${p?.class || ''}`.trim() }, c)
|
||||
export const MenuTitle = (p, c) => li({ ...p, class: `${'menu-title'} ${p?.class || ''}`.trim() }, c)
|
||||
export const MenuItem = (p) => li({}, a({ onmousedown: (e) => e.preventDefault(), class: p?.class || '', onclick: p.onclick }, p.label))
|
||||
export const Modal = (p, c) => h('dialog', { ...p, class: `${'modal'} ${p?.class || ''}`.trim() }, c)
|
||||
export const ModalBox = (p, c) => h('div', { ...p, class: `${'modal-box'} ${p?.class || ''}`.trim() }, c)
|
||||
export const ModalAction = (p, c) => h('div', { ...p, class: `${'modal-action'} ${p?.class || ''}`.trim() }, c)
|
||||
export const ModalBackdrop = (p) => h('form', { method: 'dialog', class: 'modal-backdrop' }, [h('button', {}, 'close')])
|
||||
export const ModalClose = (p) => h('form', { method: 'dialog' }, [h('button', { ...p, class: `${'btn btn-sm btn-circle btn-ghost absolute right-2 top-2'} ${p?.class || ''}`.trim() }, '✕')])
|
||||
export const Loading = (p, c) => h('span', { ...p, class: `${'loading loading-spinner'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Navbar = (p, c) => h('div', { ...p, class: `${'navbar'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Progress = (p) => h('progress', { ...p, class: `${'progress'} ${p?.class || ''}`.trim() })
|
||||
export const Radial = (p, c) => h("div", { class: `${'radial-progress'} ${p?.class || ''}`.trim(), style: `--value:${val(p.value) ?? 0};`, role: "progressbar", "aria-valuenow": p.value }, c)
|
||||
export const Radio = (p) => h('input', { type: 'radio', ...p, class: `${'radio'} ${p?.class || ''}`.trim() })
|
||||
export const Range = (p) => h('input', { type: 'range', ...p, class: `${'range'} ${p?.class || ''}`.trim() })
|
||||
export const Rating = (p, c) => h('div', { ...p, class: `${'rating'} ${p?.class || ''}`.trim() }, c)
|
||||
export const RatingItems = (p) => [...Array(p.count)].map((_, i) => h('input', { class: `${'mask'} ${p?.class || ''}`.trim(), name: p.name, type: 'radio', checked: () => val(p.value) === i, onchange: () => isFunc(p.value) ? p.value(i) : p.onchange?.(i) }))
|
||||
export const Select = (p, c) => h('select', { ...p, class: `${'select'} ${p?.class || ''}`.trim() }, c)
|
||||
export const SelectOption = (p, c) => h('option', { ...p, class: p?.class || '' }, c)
|
||||
export const Skeleton = (p) => h('div', { ...p, class: `${'skeleton'} ${p?.class || ''}`.trim() })
|
||||
export const SkeletonText = (p) => h('span', { ...p, class: `${'skeleton skeleton-text'} ${p?.class || ''}`.trim() })
|
||||
export const Stack = (p, c) => h('div', { ...p, class: `${'stack'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Stats = (p, c) => h('div', { ...p, class: `${'stats shadow'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Stat = (p, c) => h('div', { ...p, class: `${'stat'} ${p?.class || ''}`.trim() }, c)
|
||||
export const StatFigure = (p, c) => h('div', { ...p, class: `${'stat-figure'} ${p?.class || ''}`.trim() }, c)
|
||||
export const StatTitle = (p, c) => h('div', { ...p, class: `${'stat-title'} ${p?.class || ''}`.trim() }, c)
|
||||
export const StatValue = (p, c) => h('div', { ...p, class: `${'stat-value'} ${p?.class || ''}`.trim() }, c)
|
||||
export const StatDesc = (p, c) => h('div', { ...p, class: `${'stat-desc'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Steps = (p, c) => h('ul', { ...p, class: `${'steps'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Step = (p, c) => h("li", { ...p, class: `${'step'} ${p?.class || ''}`.trim(), "data-content": p.dataContent }, c)
|
||||
export const Swap = (p, c) => h('label', { ...p, class: `${'swap'} ${p?.class || ''}`.trim() }, c)
|
||||
export const SwapToggle = (p) => h('input', { type: 'checkbox', checked: () => val(p.value), onchange: (e) => isFunc(p.value) && p.value(e.target.checked), class: p.class })
|
||||
export const SwapOn = (p, c) => h('div', { ...p, class: `${'swap-on'} ${p?.class || ''}`.trim() }, c)
|
||||
export const SwapOff = (p, c) => h('div', { ...p, class: `${'swap-off'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Tabs = (p, c) => div({ ...p, class: `${'tabs'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Tab = (p) => {
|
||||
const close = () => p.tabs?.(p.tabs().filter((_, idx) => idx !== p.index))
|
||||
return [
|
||||
h('input', { type: 'radio', name: p.name, class: `${'tab'} ${p?.class || ''}`.trim(), checked: p.checked || undefined }),
|
||||
div({ class: `tab-content ${p?.classContent || ''}`.trim() }, p.content),
|
||||
p.closable ? span({ class: 'absolute top-2 right-2 cursor-pointer', onclick: (e) => { e.stopPropagation(); close() } }, '✕') : null
|
||||
]
|
||||
}
|
||||
export const Table = (p, c) => h('table', { ...p, class: `${'table'} ${p?.class || ''}`.trim() }, c)
|
||||
export const TableHead = (p, c) => h('thead', { ...p, class: p?.class || '' }, c)
|
||||
export const TableBody = (p, c) => h('tbody', { ...p, class: p?.class || '' }, c)
|
||||
export const TableFoot = (p, c) => h('tfoot', { ...p, class: p?.class || '' }, c)
|
||||
export const TableRow = (p, c) => h('tr', { ...p, class: p?.class || '' }, c)
|
||||
export const TableTh = (p, c) => h('th', { ...p, class: p?.class || '' }, c)
|
||||
export const TableTd = (p, c) => h('td', { ...p, class: p?.class || '' }, c)
|
||||
export const Textarea = (p) => h('textarea', { ...p, class: `${'textarea'} ${p?.class || ''}`.trim() })
|
||||
export const Textrotate = (p, c) => h('span', { ...p, class: `${'text-rotate'} ${p?.class || ''}`.trim() }, h('span', {}, c))
|
||||
export const Timeline = (p, c) => h('ul', { ...p, class: `${'timeline'} ${p?.class || ''}`.trim() }, c)
|
||||
export const Toast = (m, t = "alert-success", d = 3500) => {
|
||||
let C = document.getElementById("stc"), T, E, w = h("div", { style: "display:contents" });
|
||||
if (!C) document.body.append(C = h("div", { id: "stc", class: "fixed top-0 right-0 z-[9999] p-4 flex flex-col items-end gap-2 pointer-events-none" }));
|
||||
C.append(w);
|
||||
|
||||
const i = mount(() => {
|
||||
let v = $(0), l = $(0);
|
||||
E = () => l() || (l(1), clearTimeout(T), setTimeout(() => (i.destroy(), w.remove(), C.firstChild || C.remove()), 300));
|
||||
setTimeout(() => v(1));
|
||||
return h("div", {
|
||||
class: () => `alert alert-soft ${t} shadow-lg transition-all duration-300 inline-flex w-auto pointer-events-auto ${l() ? 'translate-x-full opacity-0' : v() ? 'translate-x-0 opacity-100' : 'translate-x-10 opacity-0'}`
|
||||
}, [
|
||||
typeof m == 'function' ? m() : typeof m == 'string' ? h("span", m) : m,
|
||||
h("button", { class: "btn btn-xs btn-circle btn-ghost", onclick: E }, h("span", { class: "icon-[lucide--x]" }))
|
||||
])
|
||||
}, w);
|
||||
|
||||
if (d > 0) T = setTimeout(E, d);
|
||||
return E;
|
||||
};
|
||||
export const Toggle = (p) => h('input', { type: 'checkbox', ...p, class: `${'toggle'} ${p?.class || ''}`.trim() })
|
||||
export const Tooltip = (p, c) => h("div", { ...p, class: `${'tooltip'} ${p?.class || ''}`.trim(), "data-tip": p.tip }, c)
|
||||
@@ -132,15 +132,15 @@ const misc = [
|
||||
'tooltip-open'
|
||||
]
|
||||
|
||||
// Unir todas las clases
|
||||
const allClasses = [
|
||||
...layout, ...icons, ...inputs, ...alerts, ...avatars,
|
||||
...badges, ...buttons, ...checkboxes, ...toggles, ...chats,
|
||||
...drawers, ...dropdowns, ...misc
|
||||
]
|
||||
// // Unir todas las clases
|
||||
// const allClasses = [
|
||||
// ...layout, ...icons, ...inputs, ...alerts, ...avatars,
|
||||
// ...badges, ...buttons, ...checkboxes, ...toggles, ...chats,
|
||||
// ...drawers, ...dropdowns, ...misc
|
||||
// ]
|
||||
|
||||
// Exportar para que Tailwind las detecte
|
||||
export const tailwindClasses = allClasses.join(' ')
|
||||
// // Exportar para que Tailwind las detecte
|
||||
// export const tailwindClasses = allClasses.join(' ')
|
||||
|
||||
// También como array para posible uso en JS
|
||||
export default allClasses
|
||||
// // También como array para posible uso en JS
|
||||
// export default allClasses
|
||||
Reference in New Issue
Block a user