@ladder-ui/field 0.2.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/dist/field.css ADDED
@@ -0,0 +1,47 @@
1
+ @layer components {
2
+ .lui-field {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: var(--lui-field-gap);
6
+ }
7
+ .lui-field--horizontal {
8
+ flex-direction: row;
9
+ align-items: center;
10
+ flex-wrap: wrap;
11
+ gap: var(--lui-field-gap);
12
+ }
13
+ .lui-field[data-disabled=true] .lui-field-label,
14
+ .lui-field[data-disabled=true] .lui-field-description {
15
+ opacity: 0.5;
16
+ }
17
+ .lui-field[data-invalid=true] .lui-field-label {
18
+ color: var(--lui-field-error-color);
19
+ }
20
+ .lui-field-label {
21
+ display: block;
22
+ color: var(--lui-field-label-color);
23
+ font-family: var(--lui-font-family);
24
+ font-size: var(--lui-field-label-size);
25
+ font-weight: 500;
26
+ line-height: 1.4;
27
+ }
28
+ .lui-field-description {
29
+ margin: 0;
30
+ color: var(--lui-field-description-color);
31
+ font-family: var(--lui-font-family);
32
+ font-size: var(--lui-field-description-size);
33
+ line-height: 1.5;
34
+ }
35
+ .lui-field-error {
36
+ margin: 0;
37
+ color: var(--lui-field-error-color);
38
+ font-family: var(--lui-font-family);
39
+ font-size: var(--lui-field-error-size);
40
+ line-height: 1.5;
41
+ }
42
+ .lui-field-group {
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: var(--lui-field-group-gap);
46
+ }
47
+ }
@@ -0,0 +1,97 @@
1
+ import type { HTMLAttributes, Ref } from "react";
2
+ import { type LabelProps } from "@ladder-ui/label";
3
+ export interface FieldProps extends HTMLAttributes<HTMLDivElement> {
4
+ /** React 19 ref — points to the wrapper `<div>` */
5
+ ref?: Ref<HTMLDivElement>;
6
+ /**
7
+ * Layout orientation.
8
+ * - `"vertical"` (default): label stacked above the control
9
+ * - `"horizontal"`: label and control side by side
10
+ */
11
+ orientation?: "vertical" | "horizontal";
12
+ }
13
+ /**
14
+ * Field — semantic wrapper for a single form field.
15
+ *
16
+ * Provides layout (label + control + description + error) and propagates
17
+ * disabled/invalid state to child components via `data-disabled` / `data-invalid`
18
+ * HTML attributes, which are picked up by CSS selectors.
19
+ *
20
+ * Usage:
21
+ * ```tsx
22
+ * <Field>
23
+ * <FieldLabel htmlFor="email">Email</FieldLabel>
24
+ * <Input id="email" type="email" />
25
+ * <FieldDescription>We'll never share your email.</FieldDescription>
26
+ * </Field>
27
+ *
28
+ * <Field data-invalid="true">
29
+ * <FieldLabel htmlFor="user">Username</FieldLabel>
30
+ * <Input id="user" status="error" aria-invalid="true" />
31
+ * <FieldError>Username already taken.</FieldError>
32
+ * </Field>
33
+ * ```
34
+ */
35
+ export declare function Field({ ref, className, orientation, ...props }: FieldProps): import("react/jsx-runtime").JSX.Element;
36
+ export declare namespace Field {
37
+ var displayName: string;
38
+ }
39
+ export interface FieldLabelProps extends LabelProps {
40
+ /**
41
+ * React 19 ref — points to the `<label>` element.
42
+ * Inherited from LabelProps.
43
+ */
44
+ ref?: Ref<HTMLLabelElement>;
45
+ }
46
+ /**
47
+ * FieldLabel — a `Label` scoped to a `Field` compound component.
48
+ *
49
+ * Wraps `@ladder-ui/label`'s `Label` and adds the `lui-field-label` class so
50
+ * the parent `Field` can apply context-aware styles:
51
+ * - Dims when `<Field data-disabled="true">` is set
52
+ * - Turns error-color when `<Field data-invalid="true">` is set
53
+ *
54
+ * For labels **outside a Field** context, use `Label` from `@ladder-ui/label`
55
+ * directly — it provides the same accessible `<label>` element with styling
56
+ * but without the Field-specific context.
57
+ */
58
+ export declare function FieldLabel({ ref, className, ...props }: FieldLabelProps): import("react/jsx-runtime").JSX.Element;
59
+ export declare namespace FieldLabel {
60
+ var displayName: string;
61
+ }
62
+ export interface FieldDescriptionProps extends HTMLAttributes<HTMLParagraphElement> {
63
+ /** React 19 ref — points to the `<p>` element */
64
+ ref?: Ref<HTMLParagraphElement>;
65
+ }
66
+ /**
67
+ * FieldDescription — muted helper text rendered below the control.
68
+ * Dims automatically when the parent `<Field>` has `data-disabled="true"`.
69
+ */
70
+ export declare function FieldDescription({ ref, className, ...props }: FieldDescriptionProps): import("react/jsx-runtime").JSX.Element;
71
+ export declare namespace FieldDescription {
72
+ var displayName: string;
73
+ }
74
+ export interface FieldErrorProps extends HTMLAttributes<HTMLParagraphElement> {
75
+ /** React 19 ref — points to the `<p>` element */
76
+ ref?: Ref<HTMLParagraphElement>;
77
+ }
78
+ /**
79
+ * FieldError — error text rendered below the control.
80
+ * Has `role="alert"` for live-region announcements.
81
+ * Only meaningful when the parent `<Field>` has `data-invalid="true"`.
82
+ */
83
+ export declare function FieldError({ ref, className, ...props }: FieldErrorProps): import("react/jsx-runtime").JSX.Element;
84
+ export declare namespace FieldError {
85
+ var displayName: string;
86
+ }
87
+ export interface FieldGroupProps extends HTMLAttributes<HTMLDivElement> {
88
+ /** React 19 ref — points to the wrapper `<div>` */
89
+ ref?: Ref<HTMLDivElement>;
90
+ }
91
+ /**
92
+ * FieldGroup — groups multiple `<Field>` elements with a consistent vertical gap.
93
+ */
94
+ export declare function FieldGroup({ ref, className, ...props }: FieldGroupProps): import("react/jsx-runtime").JSX.Element;
95
+ export declare namespace FieldGroup {
96
+ var displayName: string;
97
+ }
@@ -0,0 +1,15 @@
1
+ @charset "UTF-8";
2
+ :root {
3
+ /* Layout */
4
+ --lui-field-gap: 0.375rem;
5
+ --lui-field-group-gap: 1rem;
6
+ /* Label — field-specific overrides of @ladder-ui/label base tokens */
7
+ --lui-field-label-color: var(--lui-surface-text);
8
+ --lui-field-label-size: var(--lui-font-size-sm);
9
+ /* Description */
10
+ --lui-field-description-color: color-mix(in srgb, var(--lui-surface-text) 60%, transparent);
11
+ --lui-field-description-size: var(--lui-font-size-xs);
12
+ /* Error */
13
+ --lui-field-error-color: var(--lui-error);
14
+ --lui-field-error-size: var(--lui-font-size-xs);
15
+ }
@@ -0,0 +1,2 @@
1
+ export { Field, FieldLabel, FieldDescription, FieldError, FieldGroup } from "./field";
2
+ export type { FieldProps, FieldLabelProps, FieldDescriptionProps, FieldErrorProps, FieldGroupProps, } from "./field";
package/dist/index.js ADDED
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var concatClassNames = require('@ladder-ui/core/concatClassNames');
5
+ var label = require('@ladder-ui/label');
6
+
7
+ /**
8
+ * Field — semantic wrapper for a single form field.
9
+ *
10
+ * Provides layout (label + control + description + error) and propagates
11
+ * disabled/invalid state to child components via `data-disabled` / `data-invalid`
12
+ * HTML attributes, which are picked up by CSS selectors.
13
+ *
14
+ * Usage:
15
+ * ```tsx
16
+ * <Field>
17
+ * <FieldLabel htmlFor="email">Email</FieldLabel>
18
+ * <Input id="email" type="email" />
19
+ * <FieldDescription>We'll never share your email.</FieldDescription>
20
+ * </Field>
21
+ *
22
+ * <Field data-invalid="true">
23
+ * <FieldLabel htmlFor="user">Username</FieldLabel>
24
+ * <Input id="user" status="error" aria-invalid="true" />
25
+ * <FieldError>Username already taken.</FieldError>
26
+ * </Field>
27
+ * ```
28
+ */
29
+ function Field({ ref, className, orientation = "vertical", ...props }) {
30
+ return (jsxRuntime.jsx("div", { ref: ref, className: concatClassNames("lui-field", orientation === "horizontal" && "lui-field--horizontal", className), ...props }));
31
+ }
32
+ Field.displayName = "Field";
33
+ /**
34
+ * FieldLabel — a `Label` scoped to a `Field` compound component.
35
+ *
36
+ * Wraps `@ladder-ui/label`'s `Label` and adds the `lui-field-label` class so
37
+ * the parent `Field` can apply context-aware styles:
38
+ * - Dims when `<Field data-disabled="true">` is set
39
+ * - Turns error-color when `<Field data-invalid="true">` is set
40
+ *
41
+ * For labels **outside a Field** context, use `Label` from `@ladder-ui/label`
42
+ * directly — it provides the same accessible `<label>` element with styling
43
+ * but without the Field-specific context.
44
+ */
45
+ function FieldLabel({ ref, className, ...props }) {
46
+ return (jsxRuntime.jsx(label.Label, { ref: ref, className: concatClassNames("lui-field-label", className), ...props }));
47
+ }
48
+ FieldLabel.displayName = "FieldLabel";
49
+ /**
50
+ * FieldDescription — muted helper text rendered below the control.
51
+ * Dims automatically when the parent `<Field>` has `data-disabled="true"`.
52
+ */
53
+ function FieldDescription({ ref, className, ...props }) {
54
+ return (jsxRuntime.jsx("p", { ref: ref, className: concatClassNames("lui-field-description", className), ...props }));
55
+ }
56
+ FieldDescription.displayName = "FieldDescription";
57
+ /**
58
+ * FieldError — error text rendered below the control.
59
+ * Has `role="alert"` for live-region announcements.
60
+ * Only meaningful when the parent `<Field>` has `data-invalid="true"`.
61
+ */
62
+ function FieldError({ ref, className, ...props }) {
63
+ return (jsxRuntime.jsx("p", { ref: ref, role: "alert", className: concatClassNames("lui-field-error", className), ...props }));
64
+ }
65
+ FieldError.displayName = "FieldError";
66
+ /**
67
+ * FieldGroup — groups multiple `<Field>` elements with a consistent vertical gap.
68
+ */
69
+ function FieldGroup({ ref, className, ...props }) {
70
+ return (jsxRuntime.jsx("div", { ref: ref, className: concatClassNames("lui-field-group", className), ...props }));
71
+ }
72
+ FieldGroup.displayName = "FieldGroup";
73
+
74
+ exports.Field = Field;
75
+ exports.FieldDescription = FieldDescription;
76
+ exports.FieldError = FieldError;
77
+ exports.FieldGroup = FieldGroup;
78
+ exports.FieldLabel = FieldLabel;
package/dist/index.mjs ADDED
@@ -0,0 +1,72 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import concatClassNames from '@ladder-ui/core/concatClassNames';
3
+ import { Label } from '@ladder-ui/label';
4
+
5
+ /**
6
+ * Field — semantic wrapper for a single form field.
7
+ *
8
+ * Provides layout (label + control + description + error) and propagates
9
+ * disabled/invalid state to child components via `data-disabled` / `data-invalid`
10
+ * HTML attributes, which are picked up by CSS selectors.
11
+ *
12
+ * Usage:
13
+ * ```tsx
14
+ * <Field>
15
+ * <FieldLabel htmlFor="email">Email</FieldLabel>
16
+ * <Input id="email" type="email" />
17
+ * <FieldDescription>We'll never share your email.</FieldDescription>
18
+ * </Field>
19
+ *
20
+ * <Field data-invalid="true">
21
+ * <FieldLabel htmlFor="user">Username</FieldLabel>
22
+ * <Input id="user" status="error" aria-invalid="true" />
23
+ * <FieldError>Username already taken.</FieldError>
24
+ * </Field>
25
+ * ```
26
+ */
27
+ function Field({ ref, className, orientation = "vertical", ...props }) {
28
+ return (jsx("div", { ref: ref, className: concatClassNames("lui-field", orientation === "horizontal" && "lui-field--horizontal", className), ...props }));
29
+ }
30
+ Field.displayName = "Field";
31
+ /**
32
+ * FieldLabel — a `Label` scoped to a `Field` compound component.
33
+ *
34
+ * Wraps `@ladder-ui/label`'s `Label` and adds the `lui-field-label` class so
35
+ * the parent `Field` can apply context-aware styles:
36
+ * - Dims when `<Field data-disabled="true">` is set
37
+ * - Turns error-color when `<Field data-invalid="true">` is set
38
+ *
39
+ * For labels **outside a Field** context, use `Label` from `@ladder-ui/label`
40
+ * directly — it provides the same accessible `<label>` element with styling
41
+ * but without the Field-specific context.
42
+ */
43
+ function FieldLabel({ ref, className, ...props }) {
44
+ return (jsx(Label, { ref: ref, className: concatClassNames("lui-field-label", className), ...props }));
45
+ }
46
+ FieldLabel.displayName = "FieldLabel";
47
+ /**
48
+ * FieldDescription — muted helper text rendered below the control.
49
+ * Dims automatically when the parent `<Field>` has `data-disabled="true"`.
50
+ */
51
+ function FieldDescription({ ref, className, ...props }) {
52
+ return (jsx("p", { ref: ref, className: concatClassNames("lui-field-description", className), ...props }));
53
+ }
54
+ FieldDescription.displayName = "FieldDescription";
55
+ /**
56
+ * FieldError — error text rendered below the control.
57
+ * Has `role="alert"` for live-region announcements.
58
+ * Only meaningful when the parent `<Field>` has `data-invalid="true"`.
59
+ */
60
+ function FieldError({ ref, className, ...props }) {
61
+ return (jsx("p", { ref: ref, role: "alert", className: concatClassNames("lui-field-error", className), ...props }));
62
+ }
63
+ FieldError.displayName = "FieldError";
64
+ /**
65
+ * FieldGroup — groups multiple `<Field>` elements with a consistent vertical gap.
66
+ */
67
+ function FieldGroup({ ref, className, ...props }) {
68
+ return (jsx("div", { ref: ref, className: concatClassNames("lui-field-group", className), ...props }));
69
+ }
70
+ FieldGroup.displayName = "FieldGroup";
71
+
72
+ export { Field, FieldDescription, FieldError, FieldGroup, FieldLabel };
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@ladder-ui/field",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "require": "./dist/index.js",
11
+ "import": "./dist/index.mjs",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./*.css": "./dist/*.css",
15
+ "./styles/*.css": "./dist/*.css"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "keywords": [
21
+ "nodejs",
22
+ "react",
23
+ "ui",
24
+ "components",
25
+ "library",
26
+ "field",
27
+ "form",
28
+ "label"
29
+ ],
30
+ "author": "Ivan Avila <ivelaval@gmail.com> - https://www.vennet.dev",
31
+ "license": "ISC",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+ssh://git@github.com/ivelaval/ladder-ui.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/ivelaval/ladder-ui/issues"
38
+ },
39
+ "homepage": "https://github.com/ivelaval/ladder-ui#readme",
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "devDependencies": {
44
+ "@rollup/plugin-typescript": "^11.1.6",
45
+ "@types/react": "^19.0.0",
46
+ "rollup": "^4.59.0",
47
+ "rollup-plugin-postcss": "^4.0.2",
48
+ "sass": "^1.90.0",
49
+ "tslib": "^2.6.2",
50
+ "typescript": "^5.3.3",
51
+ "@ladder-ui/core": "0.2.0",
52
+ "@ladder-ui/label": "0.2.0"
53
+ },
54
+ "peerDependencies": {
55
+ "@ladder-ui/core": ">=0.0.0",
56
+ "@ladder-ui/label": ">=0.0.0",
57
+ "react": ">=18.0.0"
58
+ },
59
+ "sideEffects": [
60
+ "**/*.css"
61
+ ],
62
+ "scripts": {
63
+ "build": "pnpm clean && rollup -c",
64
+ "dev": "rollup -c -w",
65
+ "test": "vitest run",
66
+ "test:watch": "vitest",
67
+ "type-check": "tsc --noEmit",
68
+ "clean": "rm -rf dist"
69
+ }
70
+ }