release: WRNexusJS 0.4.0

This commit is contained in:
2026-07-27 12:42:18 +05:30
parent 8b728a3e5d
commit 30e5721e84
250 changed files with 10065 additions and 3923 deletions
+2 -2
View File
@@ -36,9 +36,9 @@ Theme-aware, responsive copy markup component.
Theme-aware, responsive input number component.
- Mount: `data-component="InputNumber"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Input Number"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "number"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""`, `id: string = ""`, `name: string = "quantity"`, `value: number = 0`, `min: string = ""`, `max: string = ""`, `step: number = 1`, `precision: string = "auto"`, `label: string = ""`, `description: string = ""`, `helpText: string = ""`, `error: string = ""`, `invalid: boolean = false`, `prefix: string = ""`, `suffix: string = ""`, `placeholder: string = ""`, `autocomplete: string = "off"`, `inputMode: string = "decimal"`, `ariaLabel: string = ""`, `required: boolean = false`, `disabled: boolean = false`, `inputDisabled: boolean = false`, `buttonsDisabled: boolean = false`, `readonly: boolean = false`, `allowInput: boolean = true`, `keyboard: boolean = true`, `wheel: boolean = false`, `clamp: boolean = true`, `fullWidth: boolean = false`, `showButtons: boolean = true`, `showValidationMessage: boolean = true`, `decrementLabel: string = "Decrease value"`, `incrementLabel: string = "Increase value"`, `controlsLabel: string = "Quantity controls"`, `requiredMessage: string = "A value is required."`, `minMessage: string = "Value is below the minimum."`, `maxMessage: string = "Value is above the maximum."`
- Slots: None
- Events: None
- Events: `input`, `change`, `increment`, `decrement`
### PinInput
+14 -12
View File
@@ -15,7 +15,7 @@ driven by `var(--wire-*)` theme tokens, so components restyle instantly when the
theme changes. The tiny JS surface (`src/index.ts`) exists only so the toolchain
(CLI build + dev server) can locate the component directory and stylesheet.
The complete PDF-aligned catalog currently contains **891 components**. The
The complete PDF-aligned catalog currently contains **85 components**. The
generated `COMPONENTS.md` and `component-reference.json` files document every
mount name, prop, inferred type, default/required status, slot, event, category,
and source file directly from the packaged `.wrn` source.
@@ -35,10 +35,11 @@ In practice you rarely install this directly: `@wrnexus/cli` and
## Components
Components live as `.wrn` files under `packages/ui/components/`. The mount name
is the **lowercase file basename** (e.g. `button.wrn``data-component="button"`).
Each accepts a `class` prop (appended to its root element) and most render their
body from either a named prop or the default slot.
Components live as `.wrn` files under `packages/ui/components/`. The canonical mount
name comes from the component declaration (for example, `component Button` mounts as
`data-component="Button"`). Component lookup is case-insensitive, so existing lowercase
mounts continue to work. Each component accepts a `class` prop (appended to its root
element), and most render their body from either a named prop or the default slot.
### Layout
@@ -91,16 +92,17 @@ equivalent is exported as `@wrnexus/ui/component-reference.json`.
## API
The JS module (`@wrnexus/ui`) exposes four helpers used by the build tooling to
The JS module (`@wrnexus/ui`) exposes five helpers used by the build tooling to
locate the component assets. There is no component code to import — the components
are `.wrn` files rendered server-side.
| Export | Signature | Returns |
| ------------------ | ---------------- | ------------------------------------------------------------------------------------------ |
| `uiComponentsDir` | `() => string` | Absolute path to the `.wrn` component directory (feed to `buildRouter`'s `componentDirs`). |
| `uiCssPath` | `() => string` | Absolute path to `ui.css`. |
| `uiCss` | `() => string` | The `ui.css` file contents (all `.wire-*` classes, themed via tokens). |
| `uiComponentNames` | `() => string[]` | Sorted list of built-in component names (e.g. for `wrnexus eject` listing). |
| Export | Signature | Returns |
| ------------------ | -------------------------- | ------------------------------------------------------------------------------------------ |
| `uiComponentsDir` | `() => string` | Absolute path to the `.wrn` component directory (feed to `buildRouter`'s `componentDirs`). |
| `uiCssPath` | `() => string` | Absolute path to `ui.css`. |
| `uiCss` | `() => string` | The `ui.css` file contents (all `.wire-*` classes, themed via tokens). |
| `uiComponentNames` | `() => string[]` | Sorted list of declared built-in component names. |
| `uiComponentPath` | `(name: string) => string` | Absolute source path for a declared component name or case-insensitive alias. |
### `./ui.css` asset export
+203 -41
View File
@@ -517,7 +517,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Alert.wrn"
"source": "components/alert.wrn"
},
{
"name": "Avatar",
@@ -570,7 +570,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Avatar.wrn"
"source": "components/avatar.wrn"
},
{
"name": "AvatarGroup",
@@ -676,7 +676,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Badge.wrn"
"source": "components/badge.wrn"
},
{
"name": "Blockquote",
@@ -943,7 +943,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Button.wrn"
"source": "components/button.wrn"
},
{
"name": "ButtonGroup",
@@ -1049,7 +1049,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Card.wrn"
"source": "components/card.wrn"
},
{
"name": "Carousel",
@@ -1267,7 +1267,7 @@
],
"slots": [],
"events": [],
"source": "components/Checkbox.wrn"
"source": "components/checkbox.wrn"
},
{
"name": "Clipboard",
@@ -1754,7 +1754,7 @@
],
"slots": [],
"events": ["search", "select", "change", "clear", "open", "close", "load", "error"],
"source": "components/ComboBox.wrn"
"source": "components/Combobox.wrn"
},
{
"name": "Confetti",
@@ -1854,7 +1854,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Container.wrn"
"source": "components/container.wrn"
},
{
"name": "ContextMenu",
@@ -2338,7 +2338,7 @@
],
"slots": [],
"events": [],
"source": "components/Divider.wrn"
"source": "components/divider.wrn"
},
{
"name": "DragAndDrop",
@@ -2751,7 +2751,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Grid.wrn"
"source": "components/grid.wrn"
},
{
"name": "Image",
@@ -2905,7 +2905,7 @@
],
"slots": [],
"events": [],
"source": "components/Input.wrn"
"source": "components/input.wrn"
},
{
"name": "InputGroup",
@@ -3015,34 +3015,34 @@
"default": "\"primary\""
},
{
"name": "label",
"name": "variant",
"type": "string",
"required": false,
"default": "\"Input Number\""
"default": "\"default\""
},
{
"name": "class",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "id",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "name",
"type": "string",
"required": false,
"default": "\"\""
"default": "\"quantity\""
},
{
"name": "value",
"type": "string",
"type": "number",
"required": false,
"default": "\"\""
},
{
"name": "placeholder",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "type",
"type": "string",
"required": false,
"default": "\"number\""
"default": "0"
},
{
"name": "min",
@@ -3058,16 +3058,82 @@
},
{
"name": "step",
"type": "number",
"required": false,
"default": "1"
},
{
"name": "precision",
"type": "string",
"required": false,
"default": "\"auto\""
},
{
"name": "label",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "disabled",
"name": "description",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "helpText",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "error",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "invalid",
"type": "boolean",
"required": false,
"default": "false"
},
{
"name": "prefix",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "suffix",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "placeholder",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "autocomplete",
"type": "string",
"required": false,
"default": "\"off\""
},
{
"name": "inputMode",
"type": "string",
"required": false,
"default": "\"decimal\""
},
{
"name": "ariaLabel",
"type": "string",
"required": false,
"default": "\"\""
},
{
"name": "required",
"type": "boolean",
@@ -3075,14 +3141,110 @@
"default": "false"
},
{
"name": "class",
"name": "disabled",
"type": "boolean",
"required": false,
"default": "false"
},
{
"name": "inputDisabled",
"type": "boolean",
"required": false,
"default": "false"
},
{
"name": "buttonsDisabled",
"type": "boolean",
"required": false,
"default": "false"
},
{
"name": "readonly",
"type": "boolean",
"required": false,
"default": "false"
},
{
"name": "allowInput",
"type": "boolean",
"required": false,
"default": "true"
},
{
"name": "keyboard",
"type": "boolean",
"required": false,
"default": "true"
},
{
"name": "wheel",
"type": "boolean",
"required": false,
"default": "false"
},
{
"name": "clamp",
"type": "boolean",
"required": false,
"default": "true"
},
{
"name": "fullWidth",
"type": "boolean",
"required": false,
"default": "false"
},
{
"name": "showButtons",
"type": "boolean",
"required": false,
"default": "true"
},
{
"name": "showValidationMessage",
"type": "boolean",
"required": false,
"default": "true"
},
{
"name": "decrementLabel",
"type": "string",
"required": false,
"default": "\"\""
"default": "\"Decrease value\""
},
{
"name": "incrementLabel",
"type": "string",
"required": false,
"default": "\"Increase value\""
},
{
"name": "controlsLabel",
"type": "string",
"required": false,
"default": "\"Quantity controls\""
},
{
"name": "requiredMessage",
"type": "string",
"required": false,
"default": "\"A value is required.\""
},
{
"name": "minMessage",
"type": "string",
"required": false,
"default": "\"Value is below the minimum.\""
},
{
"name": "maxMessage",
"type": "string",
"required": false,
"default": "\"Value is above the maximum.\""
}
],
"slots": [],
"events": [],
"events": ["input", "change", "increment", "decrement"],
"source": "components/InputNumber.wrn"
},
{
@@ -4039,7 +4201,7 @@
],
"slots": [],
"events": [],
"source": "components/Progress.wrn"
"source": "components/progress.wrn"
},
{
"name": "Radio",
@@ -4098,7 +4260,7 @@
],
"slots": [],
"events": [],
"source": "components/Radio.wrn"
"source": "components/radio.wrn"
},
{
"name": "RangeSlider",
@@ -4453,7 +4615,7 @@
],
"slots": [],
"events": [],
"source": "components/Select.wrn"
"source": "components/select.wrn"
},
{
"name": "Sidebar",
@@ -4547,7 +4709,7 @@
],
"slots": [],
"events": [],
"source": "components/Skeleton.wrn"
"source": "components/skeleton.wrn"
},
{
"name": "Spinner",
@@ -4588,7 +4750,7 @@
],
"slots": [],
"events": [],
"source": "components/Spinner.wrn"
"source": "components/spinner.wrn"
},
{
"name": "Stepper",
@@ -4926,7 +5088,7 @@
],
"slots": [],
"events": [],
"source": "components/Switch.wrn"
"source": "components/switch.wrn"
},
{
"name": "Table",
@@ -4979,7 +5141,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Table.wrn"
"source": "components/table.wrn"
},
{
"name": "Tabs",
@@ -5103,7 +5265,7 @@
],
"slots": [],
"events": [],
"source": "components/Textarea.wrn"
"source": "components/textarea.wrn"
},
{
"name": "Timeline",
@@ -5654,7 +5816,7 @@
],
"slots": ["default"],
"events": [],
"source": "components/Tooltip.wrn"
"source": "components/tooltip.wrn"
},
{
"name": "TreeView",
+621 -18
View File
@@ -1,20 +1,623 @@
component InputNumber {
props {
size = "default"
color = "primary"
label = "Input Number"
name = ""
value = ""
placeholder = ""
type = "number"
min = ""
max = ""
step = ""
disabled = false
required = false
class = ""
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--input-number {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
}
props {
size = "default"
color = "primary"
variant = "default"
class = ""
id = ""
name = "quantity"
value = 0
min = ""
max = ""
step = 1
precision = "auto"
label = ""
description = ""
helpText = ""
error = ""
invalid = false
prefix = ""
suffix = ""
placeholder = ""
autocomplete = "off"
inputMode = "decimal"
ariaLabel = ""
required = false
disabled = false
inputDisabled = false
buttonsDisabled = false
readonly = false
allowInput = true
keyboard = true
wheel = false
clamp = true
fullWidth = false
showButtons = true
showValidationMessage = true
decrementLabel = "Decrease value"
incrementLabel = "Increase value"
controlsLabel = "Quantity controls"
requiredMessage = "A value is required."
minMessage = "Value is below the minimum."
maxMessage = "Value is above the maximum."
@event input = function
@event change = function
@event increment = function
@event decrement = function
}
state currentValue = value
state committedValue = value
functions {
function inputId() {
if (id !== "") {
return id
}
if (name !== "") {
return name
}
return "input-number"
}
function descriptionId() {
return inputId() + "-description"
}
function messageId() {
return inputId() + "-message"
}
function componentColor() {
if (color === "secondary") {
return "var(--wire-color-secondary)"
}
if (color === "success") {
return "var(--wire-color-success)"
}
if (color === "warning") {
return "var(--wire-color-warning)"
}
if (color === "danger") {
return "var(--wire-color-danger)"
}
if (color === "info") {
return "var(--wire-color-info)"
}
return "var(--wire-color-primary)"
}
function hasMin() {
return min !== "" && min !== null && min !== undefined
}
function hasMax() {
return max !== "" && max !== null && max !== undefined
}
function isBlank() {
return currentValue === "" || currentValue === null || currentValue === undefined
}
function normalizedStep() {
return Number(step) > 0 ? Number(step) : 1
}
function inferredPrecision() {
if (precision !== "auto" && precision !== "") {
return Math.max(0, Number(precision) || 0)
}
if (String(normalizedStep()).includes(".")) {
return String(normalizedStep()).split(".")[1].length
}
return 0
}
function precisionFactor() {
return Math.pow(10, inferredPrecision())
}
function roundValue(nextValue) {
return Math.round(Number(nextValue) * precisionFactor()) / precisionFactor()
}
function clampValue(nextValue) {
nextValue = Number(nextValue)
if (hasMin() && nextValue < Number(min)) {
nextValue = Number(min)
}
if (hasMax() && nextValue > Number(max)) {
nextValue = Number(max)
}
return roundValue(nextValue)
}
function isBelowMin() {
return !isBlank() && hasMin() && Number(currentValue) < Number(min)
}
function isAboveMax() {
return !isBlank() && hasMax() && Number(currentValue) > Number(max)
}
function isInvalid() {
return (
invalid ||
error !== "" ||
(required && isBlank()) ||
isBelowMin() ||
isAboveMax()
)
}
function validationMessage() {
if (error !== "") {
return error
}
if (required && isBlank()) {
return requiredMessage
}
if (isBelowMin()) {
return minMessage
}
if (isAboveMax()) {
return maxMessage
}
return ""
}
function hasMessage() {
return (
helpText !== "" ||
(showValidationMessage && isInvalid() && validationMessage() !== "")
)
}
function describedBy() {
if (description !== "" && hasMessage()) {
return descriptionId() + " " + messageId()
}
if (description !== "") {
return descriptionId()
}
if (hasMessage()) {
return messageId()
}
return ""
}
function decrementDisabled() {
return (
disabled ||
readonly ||
buttonsDisabled ||
(hasMin() && !isBlank() && Number(currentValue) <= Number(min))
)
}
function incrementDisabled() {
return (
disabled ||
readonly ||
buttonsDisabled ||
(hasMax() && !isBlank() && Number(currentValue) >= Number(max))
)
}
function dispatchInputNumberEvent(
sourceEvent,
eventName,
action,
previousValue,
root,
customEvent
) {
root = sourceEvent.currentTarget.closest("[data-wrn-input-number]")
if (!root && sourceEvent.target) {
root = sourceEvent.target.closest("[data-wrn-input-number]")
}
if (!root) {
return
}
customEvent = document.createEvent("CustomEvent")
customEvent.initCustomEvent(eventName, true, false, {
component: "InputNumber",
name: name,
value: currentValue,
previousValue: previousValue,
action: action,
min: hasMin() ? Number(min) : null,
max: hasMax() ? Number(max) : null,
step: normalizedStep(),
valid: !isInvalid()
})
root.dispatchEvent(customEvent)
}
function applyControlValue(nextValue, action, sourceEvent, previousValue) {
previousValue = currentValue
currentValue = clampValue(nextValue)
committedValue = currentValue
dispatchInputNumberEvent(
sourceEvent,
"input",
action,
previousValue
)
dispatchInputNumberEvent(
sourceEvent,
"change",
action,
previousValue
)
dispatchInputNumberEvent(
sourceEvent,
action,
action,
previousValue
)
}
function incrementValue(sourceEvent, nextValue) {
if (incrementDisabled()) {
return
}
if (isBlank()) {
nextValue = hasMin() ? Number(min) : normalizedStep()
} else {
nextValue =
Number(currentValue) +
normalizedStep() * (sourceEvent.shiftKey ? 10 : 1)
}
applyControlValue(nextValue, "increment", sourceEvent)
}
function decrementValue(sourceEvent, nextValue) {
if (decrementDisabled()) {
return
}
if (isBlank()) {
nextValue = hasMax() ? Number(max) : -normalizedStep()
} else {
nextValue =
Number(currentValue) -
normalizedStep() * (sourceEvent.shiftKey ? 10 : 1)
}
applyControlValue(nextValue, "decrement", sourceEvent)
}
function handleInput(sourceEvent, previousValue, nextValue) {
sourceEvent.stopPropagation()
previousValue = currentValue
nextValue = sourceEvent.target.value
if (nextValue === "") {
currentValue = ""
} else if (!Number.isNaN(Number(nextValue))) {
currentValue = roundValue(Number(nextValue))
}
dispatchInputNumberEvent(
sourceEvent,
"input",
"input",
previousValue
)
}
function handleChange(sourceEvent, previousValue) {
sourceEvent.stopPropagation()
previousValue = committedValue
if (!isBlank()) {
currentValue = clamp
? clampValue(currentValue)
: roundValue(currentValue)
}
committedValue = currentValue
dispatchInputNumberEvent(
sourceEvent,
"change",
"change",
previousValue
)
}
function handleKeydown(sourceEvent) {
if (
!keyboard ||
disabled ||
readonly ||
inputDisabled ||
!allowInput
) {
return
}
if (sourceEvent.key === "ArrowUp") {
sourceEvent.preventDefault()
incrementValue(sourceEvent)
} else if (sourceEvent.key === "ArrowDown") {
sourceEvent.preventDefault()
decrementValue(sourceEvent)
} else if (sourceEvent.key === "Home" && hasMin()) {
sourceEvent.preventDefault()
applyControlValue(Number(min), "decrement", sourceEvent)
} else if (sourceEvent.key === "End" && hasMax()) {
sourceEvent.preventDefault()
applyControlValue(Number(max), "increment", sourceEvent)
}
}
function handleWheel(sourceEvent) {
if (
!wheel ||
disabled ||
readonly ||
inputDisabled ||
!allowInput
) {
return
}
sourceEvent.preventDefault()
if (sourceEvent.deltaY < 0) {
incrementValue(sourceEvent)
} else if (sourceEvent.deltaY > 0) {
decrementValue(sourceEvent)
}
}
}
view {
<div
{...attrs}
data-wrn-input-number
data-variant='{variant}'
data-size='{size}'
data-color='{color}'
data-value='{currentValue}'
data-invalid='{isInvalid() ? "true" : "false"}'
data-disabled='{disabled ? "true" : "false"}'
style='--input-number-accent: {componentColor()};'
class='relative flex flex-col gap-1.5 text-[var(--wire-color-text)] {fullWidth ? "w-full" : variant === "compact" ? "w-fit max-w-full" : "w-full max-w-sm"} {disabled ? "opacity-60" : ""} {class}'
>
{#if label !== "" && variant !== "labeled" && variant !== "seat"}
<label
for='{inputId()}'
class='inline-flex items-center gap-1 text-sm font-semibold leading-5 text-[var(--wire-color-text)]'
>
<span>{label}</span>
{#if required}
<span
aria-hidden="true"
class='text-[var(--wire-color-danger)]'
>*</span>
{/if}
</label>
{/if}
{#if description !== "" && variant !== "labeled" && variant !== "seat"}
<p
id='{descriptionId()}'
class='m-0 text-xs leading-5 text-[var(--wire-color-muted)]'
>
{description}
</p>
{/if}
<div
class='group flex min-w-0 overflow-hidden border bg-[var(--wire-color-surface)] text-[var(--wire-color-text)] shadow-[var(--wire-shadow-1)] transition-[border-color,box-shadow,background-color] duration-[var(--wire-motion-base)] ease-[var(--wire-ease-standard)] focus-within:border-[var(--input-number-accent)] focus-within:shadow-[0_0_0_3px_color-mix(in_srgb,var(--input-number-accent)_18%,transparent)] {variant === "compact" ? "rounded-full" : "rounded-[var(--wire-radius-sm)]"} {size === "xs" ? "min-h-8 text-xs" : size === "sm" ? "min-h-9 text-sm" : size === "lg" ? "min-h-12 text-base" : size === "xl" ? "min-h-14 text-lg" : "min-h-10 text-sm"} {isInvalid() ? "border-[var(--wire-color-danger)] focus-within:border-[var(--wire-color-danger)] focus-within:shadow-[0_0_0_3px_color-mix(in_srgb,var(--wire-color-danger)_18%,transparent)]" : "border-[var(--wire-color-border)]"} {disabled ? "cursor-not-allowed bg-[var(--wire-color-surface-2)]" : ""}'
>
{#if variant === "horizontal" && showButtons}
<button
type="button"
aria-label='{decrementLabel}'
aria-controls='{inputId()}'
disabled='{decrementDisabled()}'
@click='decrementValue(event)'
class='inline-flex shrink-0 items-center justify-center border-r border-[var(--wire-color-border)] bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}'
>
<span
aria-hidden="true"
class='icon-[lucide--minus] size-4'
></span>
</button>
{/if}
<div
class='flex min-w-0 flex-1 {variant === "labeled" ? "flex-col items-stretch justify-center gap-0.5" : variant === "seat" ? "items-center justify-between gap-3" : "items-center"} {size === "xs" ? "px-2" : size === "sm" ? "px-2.5" : size === "lg" ? "px-4" : size === "xl" ? "px-5" : "px-3"}'
>
{#if variant === "labeled" || variant === "seat"}
<div class='min-w-0 flex-1'>
{#if label !== ""}
<label
for='{inputId()}'
class='block truncate font-semibold leading-4 text-[var(--wire-color-text)] {variant === "labeled" ? "text-xs font-medium text-[var(--wire-color-muted)]" : "text-sm"}'
>
{label}
{#if required}
<span
aria-hidden="true"
class='ml-0.5 text-[var(--wire-color-danger)]'
>*</span>
{/if}
</label>
{/if}
{#if description !== ""}
<span
id='{descriptionId()}'
class='block truncate text-xs leading-4 text-[var(--wire-color-muted)]'
>
{description}
</span>
{/if}
</div>
{/if}
<div
class='flex min-w-0 items-center {variant === "seat" ? "w-auto shrink-0" : "w-full"}'
>
{#if prefix !== ""}
<span
aria-hidden="true"
class='shrink-0 pr-1.5 text-[var(--wire-color-muted)]'
>
{prefix}
</span>
{/if}
<input
id='{inputId()}'
name='{name}'
type="number"
value='{currentValue}'
min='{min}'
max='{max}'
step='{normalizedStep()}'
placeholder='{placeholder}'
autocomplete='{autocomplete}'
inputmode='{inputMode}'
aria-label='{ariaLabel !== "" ? ariaLabel : label !== "" ? label : name}'
aria-describedby='{describedBy()}'
aria-invalid='{isInvalid() ? "true" : "false"}'
aria-required='{required ? "true" : "false"}'
aria-disabled='{disabled || inputDisabled ? "true" : "false"}'
required='{required}'
disabled='{disabled}'
readonly='{readonly || inputDisabled || !allowInput}'
tabindex='{inputDisabled ? "-1" : "0"}'
@input='handleInput(event)'
@change='handleChange(event)'
@keydown='handleKeydown(event)'
@wheel='handleWheel(event)'
class='min-w-0 flex-1 appearance-none border-0 bg-transparent p-0 font-medium leading-none text-[var(--wire-color-text)] outline-none placeholder:text-[var(--wire-color-muted)] read-only:cursor-default disabled:cursor-not-allowed [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none {variant === "horizontal" || variant === "compact" || variant === "seat" ? "text-center" : "text-left"} {variant === "seat" ? "w-10 flex-none" : "w-full"}'
/>
{#if suffix !== ""}
<span
aria-hidden="true"
class='shrink-0 pl-1.5 text-[var(--wire-color-muted)]'
>
{suffix}
</span>
{/if}
</div>
</div>
{#if variant === "horizontal" && showButtons}
<button
type="button"
aria-label='{incrementLabel}'
aria-controls='{inputId()}'
disabled='{incrementDisabled()}'
@click='incrementValue(event)'
class='inline-flex shrink-0 items-center justify-center border-l border-[var(--wire-color-border)] bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}'
>
<span
aria-hidden="true"
class='icon-[lucide--plus] size-4'
></span>
</button>
{:else}
{#if showButtons}
<div
role="group"
aria-label='{controlsLabel}'
class='flex shrink-0 border-l border-[var(--wire-color-border)] {variant === "vertical" ? "flex-col" : "flex-row"}'
>
<button
type="button"
aria-label='{decrementLabel}'
aria-controls='{inputId()}'
disabled='{decrementDisabled()}'
@click='decrementValue(event)'
class='inline-flex items-center justify-center bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {variant === "vertical" ? "flex-1 border-b border-[var(--wire-color-border)]" : "border-r border-[var(--wire-color-border)]"} {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}'
>
<span
aria-hidden="true"
class='icon-[lucide--minus] size-4'
></span>
</button>
<button
type="button"
aria-label='{incrementLabel}'
aria-controls='{inputId()}'
disabled='{incrementDisabled()}'
@click='incrementValue(event)'
class='inline-flex items-center justify-center bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {variant === "vertical" ? "flex-1" : ""} {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}'
>
<span
aria-hidden="true"
class='icon-[lucide--plus] size-4'
></span>
</button>
</div>
{/if}
{/if}
</div>
{#if showValidationMessage && isInvalid() && validationMessage() !== ""}
<p
id='{messageId()}'
role="alert"
aria-live="polite"
class='m-0 flex items-center gap-1.5 text-xs leading-5 text-[var(--wire-color-danger)]'
>
<span
aria-hidden="true"
class='icon-[lucide--circle-alert] size-3.5 shrink-0'
></span>
<span>{validationMessage()}</span>
</p>
{/if}
{#if (!showValidationMessage || !isInvalid() || validationMessage() === "") && helpText !== ""}
<p
id='{messageId()}'
class='m-0 text-xs leading-5 text-[var(--wire-color-muted)]'
>
{helpText}
</p>
{/if}
</div>
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ui",
"version": "0.3.6",
"version": "0.4.0",
"type": "module",
"description": "@wrnexus/ui — part of the WrNexus framework.",
"license": "MIT",
@@ -26,7 +26,7 @@
"./ui.css": "./ui.css"
},
"dependencies": {
"@wrnexus/core": "^0.3.6"
"@wrnexus/core": "^0.4.0"
},
"files": [
"dist",