@muten/shadcn 0.0.7 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +47 -0
- package/README.md +47 -0
- package/kit.css +2763 -0
- package/motion.css +31 -1
- package/nova.css +1387 -0
- package/package.json +6 -2
- package/registry/accordion.muten +11 -10
- package/registry/agenda.js +35 -0
- package/registry/agenda.muten +10 -0
- package/registry/alert-dialog.muten +9 -12
- package/registry/alert.muten +8 -8
- package/registry/app-shell.js +9 -0
- package/registry/app-shell.muten +12 -0
- package/registry/attachment.muten +13 -9
- package/registry/avatar.muten +24 -5
- package/registry/badge.muten +23 -8
- package/registry/band.muten +16 -0
- package/registry/bar-chart.muten +7 -0
- package/registry/bell.muten +3 -0
- package/registry/bento.muten +6 -9
- package/registry/booking.js +21 -0
- package/registry/booking.muten +13 -0
- package/registry/breadcrumb.muten +9 -7
- package/registry/button-group.muten +13 -4
- package/registry/button.muten +21 -8
- package/registry/calendar.js +28 -93
- package/registry/calendar.muten +9 -8
- package/registry/canvas-viewport.js +12 -5
- package/registry/canvas-viewport.muten +9 -9
- package/registry/card-field.muten +4 -0
- package/registry/card.muten +12 -8
- package/registry/carousel.js +5 -36
- package/registry/carousel.muten +12 -5
- package/registry/chatbot.muten +9 -0
- package/registry/checklist.muten +6 -0
- package/registry/choice-list.muten +16 -0
- package/registry/code.js +14 -12
- package/registry/code.muten +6 -7
- package/registry/collapsible.muten +14 -10
- package/registry/color-picker.js +460 -41
- package/registry/color-picker.muten +7 -6
- package/registry/combobox.js +5 -0
- package/registry/combobox.muten +6 -23
- package/registry/command-palette.muten +8 -12
- package/registry/command.js +32 -0
- package/registry/command.muten +32 -11
- package/registry/context-menu.muten +9 -8
- package/registry/count-up.muten +5 -10
- package/registry/date-field.js +5 -0
- package/registry/date-field.muten +7 -0
- package/registry/device-frame.muten +8 -0
- package/registry/dialog.muten +6 -12
- package/registry/dirty-bar.js +19 -0
- package/registry/dirty-bar.muten +13 -0
- package/registry/drawer.muten +6 -11
- package/registry/dropdown-menu.muten +37 -13
- package/registry/empty.muten +11 -7
- package/registry/feature-grid.muten +10 -12
- package/registry/feature-rows.muten +12 -8
- package/registry/field-behavior.js +33 -0
- package/registry/field-behavior.muten +9 -0
- package/registry/field.muten +26 -7
- package/registry/file-input.js +36 -21
- package/registry/file-input.muten +8 -7
- package/registry/fixed-card.muten +25 -0
- package/registry/folder-picker.js +13 -15
- package/registry/folder-picker.muten +5 -8
- package/registry/gradient-blinds.muten +6 -13
- package/registry/hover-card.muten +7 -9
- package/registry/image-upload.js +5 -0
- package/registry/image-upload.muten +8 -0
- package/registry/indicator.muten +5 -0
- package/registry/input-group.muten +27 -4
- package/registry/input-otp.js +8 -35
- package/registry/input-otp.muten +6 -6
- package/registry/input.muten +8 -7
- package/registry/inspector.muten +13 -15
- package/registry/island.js +7 -0
- package/registry/island.muten +5 -0
- package/registry/item.muten +20 -7
- package/registry/kbd.muten +3 -3
- package/registry/kit/board.js +300 -0
- package/registry/kit/collections.js +148 -0
- package/registry/kit/core.js +989 -0
- package/registry/kit/dates.js +106 -0
- package/registry/kit/menus.js +90 -0
- package/registry/kit/overlays.js +114 -0
- package/registry/kit/paint.js +211 -0
- package/registry/kit/qrcode.js +2291 -0
- package/registry/kit/structure.js +393 -0
- package/registry/kit/table.js +198 -0
- package/registry/kit/values.js +179 -0
- package/registry/kit-layer.js +2 -0
- package/registry/kit-layer.muten +5 -0
- package/registry/kit-skeleton.js +24 -0
- package/registry/kit-skeleton.muten +16 -0
- package/registry/kit-widget.js +79 -0
- package/registry/kit-widget.muten +4 -0
- package/registry/link-btn.muten +9 -7
- package/registry/live-stack.js +29 -0
- package/registry/live-stack.muten +7 -0
- package/registry/logo-cloud.muten +6 -11
- package/registry/member-list.muten +6 -0
- package/registry/menubar.muten +10 -14
- package/registry/message-scroller.js +12 -0
- package/registry/message-scroller.muten +8 -4
- package/registry/message.muten +27 -10
- package/registry/messaging.muten +11 -0
- package/registry/modal-behavior.js +56 -0
- package/registry/modal-behavior.muten +4 -0
- package/registry/modal.muten +29 -0
- package/registry/money-field.js +5 -0
- package/registry/money-field.muten +7 -0
- package/registry/nav-button.muten +14 -0
- package/registry/navigation-menu.muten +16 -14
- package/registry/navpill.muten +15 -9
- package/registry/new-appointment.js +8 -0
- package/registry/new-appointment.muten +10 -0
- package/registry/number-field.js +34 -24
- package/registry/number-field.muten +8 -6
- package/registry/order-board.js +6 -0
- package/registry/order-board.muten +21 -0
- package/registry/overlay-behavior.js +13 -0
- package/registry/overlay-behavior.muten +4 -0
- package/registry/pagination-nav.js +6 -0
- package/registry/pagination-nav.muten +8 -0
- package/registry/pagination.muten +12 -9
- package/registry/password-field.muten +3 -0
- package/registry/permission-matrix.muten +6 -0
- package/registry/phone-field.js +5 -0
- package/registry/phone-field.muten +7 -0
- package/registry/phone-shell.js +7 -0
- package/registry/phone-shell.muten +9 -0
- package/registry/pill.muten +6 -5
- package/registry/plans.muten +4 -0
- package/registry/popover.muten +16 -9
- package/registry/pricing.muten +21 -21
- package/registry/progress.muten +5 -5
- package/registry/queue.muten +3 -0
- package/registry/radio-group.muten +16 -8
- package/registry/range-slider.js +9 -24
- package/registry/range-slider.muten +4 -5
- package/registry/resizable.js +34 -27
- package/registry/resizable.muten +16 -5
- package/registry/roving-behavior.js +16 -0
- package/registry/roving-behavior.muten +3 -0
- package/registry/row-menu.js +5 -0
- package/registry/row-menu.muten +5 -0
- package/registry/save-button.muten +11 -0
- package/registry/scale-slider.js +7 -0
- package/registry/scale-slider.muten +9 -0
- package/registry/scroll-area.muten +8 -4
- package/registry/segmented-control.muten +8 -8
- package/registry/separator.muten +3 -3
- package/registry/share-button.js +7 -0
- package/registry/share-button.muten +10 -0
- package/registry/sheet.muten +6 -10
- package/registry/sidebar.muten +23 -15
- package/registry/skeleton.muten +6 -4
- package/registry/slider.js +73 -27
- package/registry/slider.muten +6 -6
- package/registry/sortable-behavior.js +43 -0
- package/registry/sortable-behavior.muten +2 -0
- package/registry/sortable-list.js +10 -26
- package/registry/sortable-list.muten +6 -7
- package/registry/sortable.muten +15 -0
- package/registry/spark.js +14 -0
- package/registry/spark.muten +3 -0
- package/registry/spinner.muten +4 -3
- package/registry/split-button.muten +12 -10
- package/registry/stamp-card.muten +7 -0
- package/registry/stat-band.muten +6 -9
- package/registry/stat.muten +23 -0
- package/registry/status-bar.muten +7 -6
- package/registry/stepper.muten +17 -14
- package/registry/store-qr.js +5 -0
- package/registry/store-qr.muten +5 -0
- package/registry/swatch.muten +8 -8
- package/registry/switch.muten +14 -6
- package/registry/table-view.muten +10 -0
- package/registry/tabs-behavior.js +27 -0
- package/registry/tabs-behavior.muten +3 -0
- package/registry/tabs.muten +19 -10
- package/registry/tag-input.js +4 -27
- package/registry/tag-input.muten +6 -6
- package/registry/text.muten +7 -0
- package/registry/time-field.js +5 -0
- package/registry/time-field.muten +6 -0
- package/registry/timeline.muten +14 -14
- package/registry/toaster.js +34 -22
- package/registry/toaster.muten +10 -8
- package/registry/toggle-group.muten +11 -6
- package/registry/toggle.muten +8 -5
- package/registry/toolbar.muten +11 -6
- package/registry/tooltip.muten +6 -9
- package/registry/tree-view.js +27 -7
- package/registry/tree-view.muten +8 -13
- package/registry/vector-field.muten +9 -8
- package/registry/virtual-list.js +5 -0
- package/registry/virtual-list.muten +6 -0
- package/registry/weekly-hours.muten +4 -0
- package/registry/wordline.muten +6 -0
- package/registry/zoom-control.muten +9 -9
- package/registry.json +872 -406
- package/registry/context-menu.js +0 -34
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
// FolderPicker
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
export function mount(el, inputs,
|
|
5
|
-
const
|
|
6
|
-
const idle = inputs.label
|
|
7
|
-
|
|
8
|
-
el.
|
|
9
|
-
|
|
1
|
+
// FolderPicker (muten Custom) - connects a folder of the computer (the File System Access API, Chromium browsers): a
|
|
2
|
+
// button that, once a folder is chosen, shows its name. The folder's handle stays here for reading and writing.
|
|
3
|
+
// inputs: label. handlers: pick(folder name). Where the browser cannot, the button says so instead of failing.
|
|
4
|
+
export function mount(el, inputs, on) {
|
|
5
|
+
const ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/></svg>';
|
|
6
|
+
const idle = inputs.label || 'Conectar carpeta';
|
|
7
|
+
el.innerHTML = `<button type="button" data-slot="button" class="cn-button cn-button-variant-outline cn-button-size-default group/button cx-folder-btn">${ICON}<span></span></button><p class="cx-note cx-folder-msg" aria-live="polite"></p>`;
|
|
8
|
+
const btn = el.querySelector('button'), label = btn.querySelector('span'), msg = el.querySelector('.cx-folder-msg');
|
|
9
|
+
label.textContent = idle;
|
|
10
|
+
if (!window.showDirectoryPicker) { btn.disabled = true; msg.textContent = 'Este navegador no deja elegir carpetas: usa Chrome o Edge.'; }
|
|
10
11
|
btn.addEventListener('click', async () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const handle = await window.showDirectoryPicker();
|
|
14
|
-
btn.textContent = handle.name;
|
|
15
|
-
if (handlers.pick) handlers.pick(handle.name);
|
|
16
|
-
} catch (e) { /* user cancelled */ }
|
|
12
|
+
try { const handle = await window.showDirectoryPicker(); label.textContent = handle.name; btn.dataset.connected = ''; el._folder = handle; on.pick?.(handle.name); }
|
|
13
|
+
catch { /* the person closed the picker */ }
|
|
17
14
|
});
|
|
15
|
+
return () => {};
|
|
18
16
|
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
part FolderPicker(label: text, onPick: action) {
|
|
7
|
-
Custom FolderPicker inputs(label: $label) on(pick: $onPick) class("inline-flex")
|
|
8
|
-
}
|
|
1
|
+
# FolderPicker - connects a folder of the computer (Chrome and Edge): a button that shows the folder's name once it
|
|
2
|
+
# is chosen; where the browser cannot, it says so under the button instead of failing.
|
|
3
|
+
# FolderPicker(label: "Conectar carpeta", onPick: setFolder)
|
|
4
|
+
# shadcn-for-muten · Custom · host JS folder-picker.js.
|
|
5
|
+
part FolderPicker(label: text = "Conectar carpeta", onPick: action) { Custom FolderPicker inputs(label: $label) on(pick: $onPick) class("cx-folder-host") }
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
# GradientBlinds - an animated
|
|
2
|
-
# (
|
|
3
|
-
#
|
|
4
|
-
# Stack class("
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
# }
|
|
8
|
-
# `colors` = a comma-separated list of hex stops. Angle, blind count, spotlight and grain are tuned defaults in
|
|
9
|
-
# the ejected host JS - edit src/components/GradientBlinds.js to change them.
|
|
10
|
-
# shadcn-for-muten · Custom · needs `ogl` (npm i ogl). Host JS: src/components/GradientBlinds.js.
|
|
11
|
-
part GradientBlinds(colors: text) {
|
|
12
|
-
Custom GradientBlinds inputs(colors: $colors) class("absolute inset-0 z-0 pointer-events-none opacity-75")
|
|
13
|
-
}
|
|
1
|
+
# GradientBlinds - an animated gradient behind a hero: diagonal blinds and a light that follows the pointer, drawn on
|
|
2
|
+
# the GPU (WebGL, through `ogl`: npm i ogl). Make it the first child of the hero and it fills the hero, fading out
|
|
3
|
+
# at the bottom into the page; the content goes on top. colors: hex stops separated by commas.
|
|
4
|
+
# Stack class("cx-hero-blinds") { GradientBlinds(colors: "#9B80FF,#6B46F2") Stack class("…") { … } }
|
|
5
|
+
# shadcn-for-muten · Custom · needs ogl · host JS gradient-blinds.js.
|
|
6
|
+
part GradientBlinds(colors: text = "#9B80FF,#6B46F2") { Custom GradientBlinds inputs(colors: $colors) class("cx-blinds") }
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
}
|
|
1
|
+
# HoverCard - a preview that shows while the pointer rests on a name or a link (or it gets the focus), and goes
|
|
2
|
+
# away when it leaves. Only a preview: whatever matters must also be reachable without hovering.
|
|
3
|
+
# HoverCard { HoverCardTrigger { Link "@elroble" -> "/…" } HoverCardContent { … } }
|
|
4
|
+
# shadcn-for-muten · parts + Custom (OverlayBehavior) · Nova (.cn-hover-card-content) + kit.css.
|
|
5
|
+
part HoverCard() { Stack class("cx-ov") data(slot: "hover-card") { slot OverlayBehavior(kind: "hover") } }
|
|
6
|
+
part HoverCardTrigger() { Stack class("cx-ov-trigger") data(slot: "hover-card-trigger") { slot } }
|
|
7
|
+
part HoverCardContent(align: text = "center", width: text = "16rem") { Stack class("cn-hover-card-content cx-ov-content") data(slot: "hover-card-content", align: $align) style(w: "{$width}") { slot } }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ImageUpload (muten Custom) - the kit's imageUpload (kit/dates.js).
|
|
2
|
+
export function mount(el, inputs, on) {
|
|
3
|
+
Promise.all([import('@muten/shadcn/registry/kit/core.js'), import('@muten/shadcn/registry/kit/dates.js')]).then(([core, m]) => m.imageUpload(el, inputs, core, on));
|
|
4
|
+
return () => {};
|
|
5
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# ImageUpload - tap, drag or paste an image: it is checked (type, size), decoded BEFORE drawing (no black squares),
|
|
2
|
+
# cropped square, shrunk to WebP and uploaded with real progress to uploadUrl - or handed back as a data URL.
|
|
3
|
+
# onReady gets {url | dataUrl, width, height, kb} ("" when removed).
|
|
4
|
+
# ImageUpload(title: "Sube la foto del servicio", uploadUrl: "/media", onReady: setPhoto)
|
|
5
|
+
# shadcn-for-muten · Custom (kit dates) · host JS image-upload.js.
|
|
6
|
+
part ImageUpload(title: text = "Sube la foto", hint: text = "", maxMb: number = 10, size: number = 1200, uploadUrl: text = "", sample: text = "", onReady: action) {
|
|
7
|
+
Custom ImageUpload inputs(title: $title, hint: $hint, maxMb: $maxMb, size: $size, uploadUrl: $uploadUrl, sample: $sample) on(ready: $onReady) class("cx-up-host")
|
|
8
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Indicator - the dot on a corner that says «something here needs you». Inside a Btn with a tone, or on an Avatar.
|
|
2
|
+
# Btn(size: "icon-sm", variant: "ghost", tone: "note", onClick: open) { Icon "lucide:quote" Indicator(tone: "note") }
|
|
3
|
+
# tone: "" (selected) | wait | bad | info | note
|
|
4
|
+
# shadcn-for-muten · part · no deps · kit.css (.cx-indicator).
|
|
5
|
+
part Indicator(tone: text = "") { Span "" class("cx-indicator") data(slot: "indicator", tone: $tone) aria(hidden: "true") }
|
|
@@ -1,4 +1,27 @@
|
|
|
1
|
-
# InputGroup -
|
|
2
|
-
# InputGroup {
|
|
3
|
-
#
|
|
4
|
-
|
|
1
|
+
# InputGroup - a field with things inside its border: a prefix ($, an icon), a suffix (COP), a clear button.
|
|
2
|
+
# InputGroup { InputAddon { Span "$" } GroupInput(value: price) InputAddon(align: "inline-end") { Span "COP" } }
|
|
3
|
+
# SearchInput - the search with a magnifier and a × that shows only with text (Esc also clears).
|
|
4
|
+
# SearchInput(value: q, placeholder: "Nombre o teléfono", onClear: clearQ)
|
|
5
|
+
# Anything goes in an addon: an Icon, InputGroupText («https://», «COP», «@»), an InputGroupButton, a Kbd, a Spinner.
|
|
6
|
+
# align: inline-start | inline-end (beside the text) | block-start | block-end (a row above / below, for a GroupTextArea).
|
|
7
|
+
# InputGroup { GroupTextArea(value: msg, placeholder: "Escribe…") InputAddon(align: "block-end") { InputGroupText(label: "0/160") InputGroupButton(label: "Enviar", onClick: send) { Icon "lucide:send" } } }
|
|
8
|
+
# InputGroup and SearchInput take size (default | xl | 2xl) and variant (default | filled) like Input.
|
|
9
|
+
# shadcn-for-muten · part · no deps · Nova (.cn-input-group).
|
|
10
|
+
part InputGroup(size: text = "default", variant: text = "default") { Stack class("cn-input-group group/input-group") data(slot: "input-group", size: $size, variant: $variant) aria(role: "group") { slot } }
|
|
11
|
+
part InputAddon(align: text = "inline-start") { Stack class("cn-input-group-addon cn-input-group-addon-align-{$align}") data(slot: "input-group-addon", align: $align) { slot } }
|
|
12
|
+
part GroupInput(value: text, placeholder: text = "") { SearchField bind($value) "{$placeholder}" class("cn-input cn-input-group-input cx-num") data(slot: "input-group-control") }
|
|
13
|
+
part SearchInput(value: text, placeholder: text = "Buscar", onClear: action, size: text = "default", variant: text = "default") {
|
|
14
|
+
Stack class("cn-input-group group/input-group") data(slot: "input-group", size: $size, variant: $variant) aria(role: "group") {
|
|
15
|
+
Stack class("cn-input-group-addon cn-input-group-addon-align-inline-start") data(slot: "input-group-addon", align: "inline-start") { Icon "lucide:search" }
|
|
16
|
+
SearchField bind($value) "{$placeholder}" class("cn-input cn-input-group-input") data(slot: "input-group-control")
|
|
17
|
+
Stack class("cn-input-group-addon cn-input-group-addon-align-inline-end") data(slot: "input-group-addon", align: "inline-end") {
|
|
18
|
+
when $value != "" { Button -> $onClear class("cn-button cn-button-variant-ghost cn-button-size-icon-xs group/button cx-clear") aria(label: "Limpiar búsqueda") { Icon "lucide:x" } }
|
|
19
|
+
}
|
|
20
|
+
FieldBehavior(kind: "search", message: "")
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
part InputGroupText(label: text) { Span "{$label}" class("cn-input-group-text") data(slot: "input-group-text") }
|
|
24
|
+
part InputGroupButton(onClick: action, variant: text = "ghost", size: text = "xs", label: text = "") {
|
|
25
|
+
Button -> $onClick class("cn-button cn-button-variant-{$variant} cn-input-group-button cn-input-group-button-size-{$size} group/button") data(slot: "button", size: $size, name: $label) aria(label: $label) { slot }
|
|
26
|
+
}
|
|
27
|
+
part GroupTextArea(value: text, placeholder: text = "") { Textarea bind($value) "{$placeholder}" class("cn-textarea cn-input-group-textarea") data(slot: "input-group-control") }
|
package/registry/input-otp.js
CHANGED
|
@@ -1,36 +1,9 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
export function mount(el, inputs,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const box = document.createElement('input');
|
|
10
|
-
box.className = 'otp-slot';
|
|
11
|
-
box.maxLength = 1;
|
|
12
|
-
box.inputMode = 'numeric';
|
|
13
|
-
box.autocomplete = 'one-time-code';
|
|
14
|
-
box.addEventListener('input', () => {
|
|
15
|
-
box.value = box.value.replace(/\D/g, '').slice(-1);
|
|
16
|
-
if (box.value && i < len - 1) boxes[i + 1].focus();
|
|
17
|
-
emit();
|
|
18
|
-
});
|
|
19
|
-
box.addEventListener('keydown', (e) => {
|
|
20
|
-
if (e.key === 'Backspace' && !box.value && i > 0) boxes[i - 1].focus();
|
|
21
|
-
});
|
|
22
|
-
box.addEventListener('paste', (e) => {
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
const text = ((e.clipboardData && e.clipboardData.getData('text')) || '').replace(/\D/g, '').slice(0, len);
|
|
25
|
-
for (let j = 0; j < len; j++) boxes[j].value = text[j] || '';
|
|
26
|
-
(boxes[Math.min(text.length, len - 1)] || boxes[0]).focus();
|
|
27
|
-
emit();
|
|
28
|
-
});
|
|
29
|
-
boxes.push(box);
|
|
30
|
-
el.appendChild(box);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const set = (val) => { const s = String(val == null ? '' : val); boxes.forEach((b, i) => { b.value = s[i] || ''; }); };
|
|
34
|
-
set(inputs.value);
|
|
35
|
-
return (next) => set(next.value);
|
|
1
|
+
// InputOtp (muten Custom) - the verification code: slots, caret, checking / ok / bad, resend countdown
|
|
2
|
+
// (kit/values.js otpField). The page checks the code: onInput gets it when complete; answer with state + message.
|
|
3
|
+
export function mount(el, inputs, on) {
|
|
4
|
+
let update = null;
|
|
5
|
+
Promise.all([import('@muten/shadcn/registry/kit/core.js'), import('@muten/shadcn/registry/kit/values.js')]).then(([core, v]) => {
|
|
6
|
+
update = v.otpField(el, inputs, core, { complete: (code) => (on.input || on.complete)?.(code), resend: () => on.resend?.() });
|
|
7
|
+
});
|
|
8
|
+
return (next) => update?.(next);
|
|
36
9
|
}
|
package/registry/input-otp.muten
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
# InputOtp(value: code, length: 6, onInput:
|
|
4
|
-
# shadcn-for-muten · Custom · host JS
|
|
5
|
-
part InputOtp(value: text, length: number, onInput: action) {
|
|
6
|
-
Custom InputOtp inputs(value: $value, length: $length) on(input: $onInput) class("otp")
|
|
1
|
+
# InputOtp - the verification code: slots in two groups, a caret, «Verificando…», ok / bad, a resend countdown. The
|
|
2
|
+
# PAGE checks the code: onInput gets it when complete; answer with state ("ok" | "bad") and message.
|
|
3
|
+
# InputOtp(value: code, length: 6, hint: "Te lo enviamos al +57 300 123 4567", state: otpState, message: otpMsg, onInput: check)
|
|
4
|
+
# shadcn-for-muten · Custom (kit values) · host JS input-otp.js.
|
|
5
|
+
part InputOtp(value: text = "", length: number = 6, hint: text = "", state: text = "", message: text = "", resendIn: number = 30, onInput: action) {
|
|
6
|
+
Custom InputOtp inputs(value: $value, length: $length, hint: $hint, state: $state, message: $message, resendIn: $resendIn) on(input: $onInput) class("cx-otp-host")
|
|
7
7
|
}
|
package/registry/input.muten
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
# Input
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# shadcn-for-muten · part · no deps ·
|
|
7
|
-
part Input(value: text, placeholder: text) { SearchField bind($value) "{$placeholder}" class("input") }
|
|
1
|
+
# Input - a text field bound to a page text state. TextArea - the same for several lines (`Textarea` is muten's
|
|
2
|
+
# primitive, so the part is TextArea).
|
|
3
|
+
# Input(value: name, placeholder: "Nombre o teléfono") TextArea(value: notes, placeholder: "Notas para el equipo")
|
|
4
|
+
# size: default (32) | xl (44) | 2xl (52) · variant: default (a line) | filled (the soft field of a landing: muted fill, no line).
|
|
5
|
+
# For a whole form, set them once on a FieldSet around it instead (field.muten).
|
|
6
|
+
# shadcn-for-muten · part · no deps · Nova (.cn-input, .cn-textarea).
|
|
7
|
+
part Input(value: text, placeholder: text = "", size: text = "default", variant: text = "default") { SearchField bind($value) "{$placeholder}" class("cn-input") data(slot: "input", size: $size, variant: $variant) }
|
|
8
|
+
part TextArea(value: text, placeholder: text = "") { Textarea bind($value) "{$placeholder}" class("cn-textarea") data(slot: "textarea") }
|
package/registry/inspector.muten
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
# Inspector
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
1
|
+
# Inspector - the right panel of an editor: sections that fold (Transform, Apariencia), each a list of rows with the
|
|
2
|
+
# property's name on the left and its control on the right (a NumberField, a Switch, a ColorPicker…). The page owns
|
|
3
|
+
# whether each section is open.
|
|
4
|
+
# Inspector {
|
|
5
|
+
# InspectorSection(label: "Transform", open: tOpen, onToggle: toggleT) {
|
|
6
|
+
# InspectorRow(label: "Posición") { VectorField(…) } InspectorRow(label: "Rotación") { NumberField(…) }
|
|
7
|
+
# }
|
|
5
8
|
# }
|
|
6
|
-
# shadcn-for-muten ·
|
|
7
|
-
part Inspector() { Stack class("inspector") { slot } }
|
|
9
|
+
# shadcn-for-muten · parts · no deps · kit.css (.cx-insp, the Accordion's fold).
|
|
10
|
+
part Inspector(label: text = "Propiedades") { Stack class("cx-insp") data(slot: "inspector") aria(label: $label) { slot } }
|
|
8
11
|
part InspectorSection(label: text, open: bool, onToggle: action) {
|
|
9
|
-
Stack class("
|
|
10
|
-
Button -> $onToggle aria(expanded: $open) class("
|
|
11
|
-
|
|
12
|
-
Icon "lucide:chevron-down" class("inspector-chevron", "inspector-chevron-open" when $open)
|
|
13
|
-
}
|
|
14
|
-
when $open { Stack class("inspector-body") { slot } }
|
|
12
|
+
Stack class("cx-insp-sec") data(open: $open) {
|
|
13
|
+
Button -> $onToggle class("cx-insp-head") aria(expanded: $open) { Span "{$label}" Icon "lucide:chevron-down" class("cx-acc-chev") }
|
|
14
|
+
Stack class("cn-accordion-content cx-acc-fold") data(open: $open) aria(role: "region", label: $label) { Stack class("cn-accordion-content-inner cx-insp-body") { slot } }
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
part InspectorRow(label: text) {
|
|
18
|
-
Stack class("inspector-row") { Span "{$label}" class("inspector-row-label") slot }
|
|
19
|
-
}
|
|
17
|
+
part InspectorRow(label: text) { Stack class("cx-insp-row") { Span "{$label}" class("cx-insp-label") Stack class("cx-insp-ctl") { slot } } }
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Island (muten Custom) - drives the kit's one floating notice (kit/core.js island): each new text morphs it.
|
|
2
|
+
export function mount(el, inputs) {
|
|
3
|
+
let core = null, last = '';
|
|
4
|
+
const show = (i) => { if (!core || !i.text || i.text + i.tone === last) return; last = i.text + i.tone; core.island(i.tone || 'info', i.text, Number(i.ms) || 0); };
|
|
5
|
+
import('@muten/shadcn/registry/kit/core.js').then((c) => { core = c; show(inputs); });
|
|
6
|
+
return (next) => show(next);
|
|
7
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Island - answers what the person just did (saving, saved, error) and never stacks: it changes shape and text in
|
|
2
|
+
# the same place, at the top of the app. Change `text` (and `tone`) and it morphs; ms > 0 hides it after that time.
|
|
3
|
+
# Island(tone: saveTone, text: saveText, ms: 2200) tone: say (spinner) | done | info | error
|
|
4
|
+
# Put KitLayer once in the app shell first. shadcn-for-muten · Custom (kit core) · host JS is island.js.
|
|
5
|
+
part Island(tone: text = "info", text: text, ms: number = 0) { Custom Island inputs(tone: $tone, text: $text, ms: $ms) class("cx-island-host") }
|
package/registry/item.muten
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
# Item
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
# Item - a row: media, content (title + description), actions, an optional footer. Lists are Items in an ItemGroup
|
|
2
|
+
# with ItemSeparator between them.
|
|
3
|
+
# ItemGroup {
|
|
4
|
+
# Item { ItemMedia { Avatar(name: "Ana") } ItemContent { ItemTitle(label: "Ana") ItemDescription(label: "Corte · 9:00") } ItemActions { Txt(value: "$25.000", variant: "strong") } }
|
|
5
|
+
# ItemSeparator()
|
|
6
|
+
# }
|
|
7
|
+
# Item variant: default | outline | muted · size: default | sm | xs · ItemMedia variant: default | icon | image
|
|
8
|
+
# shadcn-for-muten · part · no deps · Nova (.cn-item).
|
|
9
|
+
part Item(variant: text = "default", size: text = "default") { Stack class("cn-item cn-item-variant-{$variant} cn-item-size-{$size} group/item") data(slot: "item", size: $size) { slot } }
|
|
10
|
+
part ItemGroup() { Stack class("cn-item-group group/item-group") data(slot: "item-group") aria(role: "list") { slot } }
|
|
11
|
+
part ItemSeparator() { Stack class("cn-separator cn-separator-horizontal cn-item-separator") data(slot: "item-separator", orientation: "horizontal") aria(role: "separator") }
|
|
12
|
+
part ItemMedia(variant: text = "default") { Stack class("cn-item-media cn-item-media-variant-{$variant}") data(slot: "item-media", variant: $variant) { slot } }
|
|
13
|
+
part ItemContent() { Stack class("cn-item-content") data(slot: "item-content") { slot } }
|
|
14
|
+
part ItemTitle(label: text) { Span "{$label}" class("cn-item-title") data(slot: "item-title") }
|
|
15
|
+
part ItemDescription(label: text) { Text "{$label}" class("cn-item-description") data(slot: "item-description") }
|
|
16
|
+
part ItemActions() { Stack class("cn-item-actions") data(slot: "item-actions") { slot } }
|
|
17
|
+
part ItemFooter() { Stack class("cn-item-footer") data(slot: "item-footer") { slot } }
|
|
18
|
+
# ItemImage - a photo as an Item's media (40×40, rounded). Price - an amount with tabular digits, pushed to the end.
|
|
19
|
+
part ItemImage(src: text, alt: text = "") { Image "{$src}" alt("{$alt}") class("cx-media-img") }
|
|
20
|
+
part Price(value: text) { Span "{$value}" class("cx-price") }
|
package/registry/kbd.muten
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
# Kbd - a keyboard key
|
|
2
|
-
# shadcn-for-muten · part · no deps ·
|
|
3
|
-
part Kbd() {
|
|
1
|
+
# Kbd - a keyboard key. Kbd { Span "⌘" } Kbd { Span "K" }
|
|
2
|
+
# shadcn-for-muten · part · no deps · Nova (.cn-kbd).
|
|
3
|
+
part Kbd() { Stack class("cn-kbd") data(slot: "kbd") { slot } }
|