From 0d7b41e5752e8f11930bdf6d1c5ab3bedc7a5f9b Mon Sep 17 00:00:00 2001 From: elonehoo Date: Tue, 16 Jun 2026 23:10:48 +0800 Subject: [PATCH 1/3] feat(field): align react examples, stories and docs styles with vue - Add missing React field examples: Input, InputControlled, ReactiveInvalid, RequiredIndicator, Select, SelectControlled, Textarea, TextareaAutoresize, TextareaControlled - Export all 11 field examples in React stories - Register all 11 field examples in Vue stories - Fill docs styles for all field examples so previews render consistently Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/src/styles/components/field/basic.css | 76 +++++++++++++++ docs/src/styles/components/field/disabled.css | 76 +++++++++++++++ .../components/field/input-controlled.css | 76 +++++++++++++++ docs/src/styles/components/field/input.css | 76 +++++++++++++++ .../components/field/reactive-invalid.css | 95 +++++++++++++++++++ .../components/field/required-indicator.css | 76 +++++++++++++++ .../components/field/select-controlled.css | 76 +++++++++++++++ docs/src/styles/components/field/select.css | 76 +++++++++++++++ .../components/field/textarea-autoresize.css | 76 +++++++++++++++ .../components/field/textarea-controlled.css | 76 +++++++++++++++ docs/src/styles/components/field/textarea.css | 76 +++++++++++++++ .../src/components/field/examples/Input.tsx | 14 +++ .../field/examples/InputControlled.tsx | 20 ++++ .../field/examples/ReactiveInvalid.tsx | 23 +++++ .../field/examples/RequiredIndicator.tsx | 15 +++ .../src/components/field/examples/Select.tsx | 18 ++++ .../field/examples/SelectControlled.tsx | 24 +++++ .../components/field/examples/Textarea.tsx | 14 +++ .../field/examples/TextareaAutoresize.tsx | 14 +++ .../field/examples/TextareaControlled.tsx | 20 ++++ .../field/stories/field.stories.tsx | 9 ++ .../components/field/stories/field.stories.ts | 80 ++++++++++++++++ 22 files changed, 1106 insertions(+) create mode 100644 packages/react/src/components/field/examples/Input.tsx create mode 100644 packages/react/src/components/field/examples/InputControlled.tsx create mode 100644 packages/react/src/components/field/examples/ReactiveInvalid.tsx create mode 100644 packages/react/src/components/field/examples/RequiredIndicator.tsx create mode 100644 packages/react/src/components/field/examples/Select.tsx create mode 100644 packages/react/src/components/field/examples/SelectControlled.tsx create mode 100644 packages/react/src/components/field/examples/Textarea.tsx create mode 100644 packages/react/src/components/field/examples/TextareaAutoresize.tsx create mode 100644 packages/react/src/components/field/examples/TextareaControlled.tsx diff --git a/docs/src/styles/components/field/basic.css b/docs/src/styles/components/field/basic.css index e69de29..4fb6205 100644 --- a/docs/src/styles/components/field/basic.css +++ b/docs/src/styles/components/field/basic.css @@ -0,0 +1,76 @@ +.field-basic [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-basic [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-basic [data-part="input"], +.field-basic [data-part="select"], +.field-basic [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-basic [data-part="input"]:focus, +.field-basic [data-part="select"]:focus, +.field-basic [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-basic [data-part="input"][data-disabled], +.field-basic [data-part="select"][data-disabled], +.field-basic [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-basic [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-basic [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-basic [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-basic [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-basic [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/disabled.css b/docs/src/styles/components/field/disabled.css index e69de29..ecd2a2f 100644 --- a/docs/src/styles/components/field/disabled.css +++ b/docs/src/styles/components/field/disabled.css @@ -0,0 +1,76 @@ +.field-disabled [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-disabled [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-disabled [data-part="input"], +.field-disabled [data-part="select"], +.field-disabled [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-disabled [data-part="input"]:focus, +.field-disabled [data-part="select"]:focus, +.field-disabled [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-disabled [data-part="input"][data-disabled], +.field-disabled [data-part="select"][data-disabled], +.field-disabled [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-disabled [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-disabled [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-disabled [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-disabled [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-disabled [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/input-controlled.css b/docs/src/styles/components/field/input-controlled.css index e69de29..9c85cda 100644 --- a/docs/src/styles/components/field/input-controlled.css +++ b/docs/src/styles/components/field/input-controlled.css @@ -0,0 +1,76 @@ +.field-inputcontrolled [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-inputcontrolled [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-inputcontrolled [data-part="input"], +.field-inputcontrolled [data-part="select"], +.field-inputcontrolled [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-inputcontrolled [data-part="input"]:focus, +.field-inputcontrolled [data-part="select"]:focus, +.field-inputcontrolled [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-inputcontrolled [data-part="input"][data-disabled], +.field-inputcontrolled [data-part="select"][data-disabled], +.field-inputcontrolled [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-inputcontrolled [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-inputcontrolled [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-inputcontrolled [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-inputcontrolled [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-inputcontrolled [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/input.css b/docs/src/styles/components/field/input.css index e69de29..c6b52f7 100644 --- a/docs/src/styles/components/field/input.css +++ b/docs/src/styles/components/field/input.css @@ -0,0 +1,76 @@ +.field-input [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-input [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-input [data-part="input"], +.field-input [data-part="select"], +.field-input [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-input [data-part="input"]:focus, +.field-input [data-part="select"]:focus, +.field-input [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-input [data-part="input"][data-disabled], +.field-input [data-part="select"][data-disabled], +.field-input [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-input [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-input [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-input [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-input [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-input [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/reactive-invalid.css b/docs/src/styles/components/field/reactive-invalid.css index e69de29..3c80ce7 100644 --- a/docs/src/styles/components/field/reactive-invalid.css +++ b/docs/src/styles/components/field/reactive-invalid.css @@ -0,0 +1,95 @@ +.field-reactiveinvalid [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-reactiveinvalid [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-reactiveinvalid [data-part="input"], +.field-reactiveinvalid [data-part="select"], +.field-reactiveinvalid [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-reactiveinvalid [data-part="input"]:focus, +.field-reactiveinvalid [data-part="select"]:focus, +.field-reactiveinvalid [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-reactiveinvalid [data-part="input"][data-disabled], +.field-reactiveinvalid [data-part="select"][data-disabled], +.field-reactiveinvalid [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-reactiveinvalid [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-reactiveinvalid [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-reactiveinvalid [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-reactiveinvalid [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-reactiveinvalid [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} + +.field-reactiveinvalid > input { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + margin-bottom: 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-reactiveinvalid > input:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} diff --git a/docs/src/styles/components/field/required-indicator.css b/docs/src/styles/components/field/required-indicator.css index e69de29..017242a 100644 --- a/docs/src/styles/components/field/required-indicator.css +++ b/docs/src/styles/components/field/required-indicator.css @@ -0,0 +1,76 @@ +.field-requiredindicator [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-requiredindicator [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-requiredindicator [data-part="input"], +.field-requiredindicator [data-part="select"], +.field-requiredindicator [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-requiredindicator [data-part="input"]:focus, +.field-requiredindicator [data-part="select"]:focus, +.field-requiredindicator [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-requiredindicator [data-part="input"][data-disabled], +.field-requiredindicator [data-part="select"][data-disabled], +.field-requiredindicator [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-requiredindicator [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-requiredindicator [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-requiredindicator [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-requiredindicator [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-requiredindicator [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/select-controlled.css b/docs/src/styles/components/field/select-controlled.css index e69de29..08ca9c1 100644 --- a/docs/src/styles/components/field/select-controlled.css +++ b/docs/src/styles/components/field/select-controlled.css @@ -0,0 +1,76 @@ +.field-selectcontrolled [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-selectcontrolled [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-selectcontrolled [data-part="input"], +.field-selectcontrolled [data-part="select"], +.field-selectcontrolled [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-selectcontrolled [data-part="input"]:focus, +.field-selectcontrolled [data-part="select"]:focus, +.field-selectcontrolled [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-selectcontrolled [data-part="input"][data-disabled], +.field-selectcontrolled [data-part="select"][data-disabled], +.field-selectcontrolled [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-selectcontrolled [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-selectcontrolled [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-selectcontrolled [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-selectcontrolled [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-selectcontrolled [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/select.css b/docs/src/styles/components/field/select.css index e69de29..ab5d606 100644 --- a/docs/src/styles/components/field/select.css +++ b/docs/src/styles/components/field/select.css @@ -0,0 +1,76 @@ +.field-select [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-select [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-select [data-part="input"], +.field-select [data-part="select"], +.field-select [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-select [data-part="input"]:focus, +.field-select [data-part="select"]:focus, +.field-select [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-select [data-part="input"][data-disabled], +.field-select [data-part="select"][data-disabled], +.field-select [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-select [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-select [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-select [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-select [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-select [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/textarea-autoresize.css b/docs/src/styles/components/field/textarea-autoresize.css index e69de29..dbddb88 100644 --- a/docs/src/styles/components/field/textarea-autoresize.css +++ b/docs/src/styles/components/field/textarea-autoresize.css @@ -0,0 +1,76 @@ +.field-textareaautoresize [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-textareaautoresize [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-textareaautoresize [data-part="input"], +.field-textareaautoresize [data-part="select"], +.field-textareaautoresize [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-textareaautoresize [data-part="input"]:focus, +.field-textareaautoresize [data-part="select"]:focus, +.field-textareaautoresize [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-textareaautoresize [data-part="input"][data-disabled], +.field-textareaautoresize [data-part="select"][data-disabled], +.field-textareaautoresize [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-textareaautoresize [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-textareaautoresize [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-textareaautoresize [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-textareaautoresize [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-textareaautoresize [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/textarea-controlled.css b/docs/src/styles/components/field/textarea-controlled.css index e69de29..3fc77f3 100644 --- a/docs/src/styles/components/field/textarea-controlled.css +++ b/docs/src/styles/components/field/textarea-controlled.css @@ -0,0 +1,76 @@ +.field-textareacontrolled [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-textareacontrolled [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-textareacontrolled [data-part="input"], +.field-textareacontrolled [data-part="select"], +.field-textareacontrolled [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-textareacontrolled [data-part="input"]:focus, +.field-textareacontrolled [data-part="select"]:focus, +.field-textareacontrolled [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-textareacontrolled [data-part="input"][data-disabled], +.field-textareacontrolled [data-part="select"][data-disabled], +.field-textareacontrolled [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-textareacontrolled [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-textareacontrolled [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-textareacontrolled [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-textareacontrolled [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-textareacontrolled [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/docs/src/styles/components/field/textarea.css b/docs/src/styles/components/field/textarea.css index e69de29..25ab41a 100644 --- a/docs/src/styles/components/field/textarea.css +++ b/docs/src/styles/components/field/textarea.css @@ -0,0 +1,76 @@ +.field-textarea [data-part="root"] { + display: flex; + flex-direction: column; + gap: 0.375rem; + width: 100%; + max-width: 20rem; + font-family: inherit; + color: var(--demo-neutral-fg); +} + +.field-textarea [data-part="label"] { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; + color: var(--demo-neutral-fg); +} + +.field-textarea [data-part="input"], +.field-textarea [data-part="select"], +.field-textarea [data-part="textarea"] { + min-height: 2.25rem; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--demo-neutral-fg); + background: var(--demo-bg-checkbox); + border: 1px solid var(--demo-border-emphasized); + border-radius: 0.5rem; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field-textarea [data-part="input"]:focus, +.field-textarea [data-part="select"]:focus, +.field-textarea [data-part="textarea"]:focus { + border-color: var(--demo-coral-solid); + box-shadow: 0 0 0 2px var(--demo-coral-focus-ring); +} + +.field-textarea [data-part="input"][data-disabled], +.field-textarea [data-part="select"][data-disabled], +.field-textarea [data-part="textarea"][data-disabled] { + cursor: not-allowed; + opacity: 0.5; + background: var(--demo-neutral-subtle); +} + +.field-textarea [data-part="select"] { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2361605b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.625rem center; + padding-right: 2rem; +} + +.field-textarea [data-part="textarea"] { + min-height: 5rem; + resize: vertical; +} + +.field-textarea [data-part="helperText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-neutral-fg-muted); +} + +.field-textarea [data-part="errorText"] { + font-size: 0.75rem; + line-height: 1rem; + color: var(--demo-error); +} + +.field-textarea [data-part="requiredIndicator"] { + margin-left: 0.125rem; + color: var(--demo-error); +} diff --git a/packages/react/src/components/field/examples/Input.tsx b/packages/react/src/components/field/examples/Input.tsx new file mode 100644 index 0000000..b339a80 --- /dev/null +++ b/packages/react/src/components/field/examples/Input.tsx @@ -0,0 +1,14 @@ +import { Field } from '../index' + +export interface InputProps extends Field.RootProps {} + +export function Input(props: InputProps) { + return ( + + Label + + Some additional Info + Error Info + + ) +} diff --git a/packages/react/src/components/field/examples/InputControlled.tsx b/packages/react/src/components/field/examples/InputControlled.tsx new file mode 100644 index 0000000..ebc3cbd --- /dev/null +++ b/packages/react/src/components/field/examples/InputControlled.tsx @@ -0,0 +1,20 @@ +import { useState } from 'react' +import { Field } from '../index' + +export interface InputControlledProps extends Field.RootProps {} + +export function InputControlled(props: InputControlledProps) { + const [value, setValue] = useState('Input is controlled') + + return ( + <> + Input text: {value} + + Label + setValue(e.target.value)} /> + Some additional Info + Error Info + + + ) +} diff --git a/packages/react/src/components/field/examples/ReactiveInvalid.tsx b/packages/react/src/components/field/examples/ReactiveInvalid.tsx new file mode 100644 index 0000000..960a3b6 --- /dev/null +++ b/packages/react/src/components/field/examples/ReactiveInvalid.tsx @@ -0,0 +1,23 @@ +import { useState } from 'react' +import { Field } from '../index' + +export interface ReactiveInvalidProps extends Field.RootProps {} + +export function ReactiveInvalid(props: ReactiveInvalidProps) { + const [errorMessage, setErrorMessage] = useState('') + const invalid = !!errorMessage + + return ( + <> + setErrorMessage(e.target.value)} + placeholder="Type an error message" + /> + + IsInvalid? {String(invalid)} + {errorMessage} + + + ) +} diff --git a/packages/react/src/components/field/examples/RequiredIndicator.tsx b/packages/react/src/components/field/examples/RequiredIndicator.tsx new file mode 100644 index 0000000..8db310c --- /dev/null +++ b/packages/react/src/components/field/examples/RequiredIndicator.tsx @@ -0,0 +1,15 @@ +import { Field } from '../index' + +export interface RequiredIndicatorProps extends Field.RootProps {} + +export function RequiredIndicator(props: RequiredIndicatorProps) { + return ( + + + Username + + + + + ) +} diff --git a/packages/react/src/components/field/examples/Select.tsx b/packages/react/src/components/field/examples/Select.tsx new file mode 100644 index 0000000..5212380 --- /dev/null +++ b/packages/react/src/components/field/examples/Select.tsx @@ -0,0 +1,18 @@ +import { Field } from '../index' + +export interface SelectProps extends Field.RootProps {} + +export function Select(props: SelectProps) { + return ( + + Label + + + + + + Some additional Info + Error Info + + ) +} diff --git a/packages/react/src/components/field/examples/SelectControlled.tsx b/packages/react/src/components/field/examples/SelectControlled.tsx new file mode 100644 index 0000000..460c9d9 --- /dev/null +++ b/packages/react/src/components/field/examples/SelectControlled.tsx @@ -0,0 +1,24 @@ +import { useState } from 'react' +import { Field } from '../index' + +export interface SelectControlledProps extends Field.RootProps {} + +export function SelectControlled(props: SelectControlledProps) { + const [value, setValue] = useState('3') + + return ( + <> + Selected: Option {value} + + Label + setValue(e.target.value)}> + + + + + Some additional Info + Error Info + + + ) +} diff --git a/packages/react/src/components/field/examples/Textarea.tsx b/packages/react/src/components/field/examples/Textarea.tsx new file mode 100644 index 0000000..74f5a0b --- /dev/null +++ b/packages/react/src/components/field/examples/Textarea.tsx @@ -0,0 +1,14 @@ +import { Field } from '../index' + +export interface TextareaProps extends Field.RootProps {} + +export function Textarea(props: TextareaProps) { + return ( + + Label + + Some additional Info + Error Info + + ) +} diff --git a/packages/react/src/components/field/examples/TextareaAutoresize.tsx b/packages/react/src/components/field/examples/TextareaAutoresize.tsx new file mode 100644 index 0000000..ce184e5 --- /dev/null +++ b/packages/react/src/components/field/examples/TextareaAutoresize.tsx @@ -0,0 +1,14 @@ +import { Field } from '../index' + +export interface TextareaAutoresizeProps extends Field.RootProps {} + +export function TextareaAutoresize(props: TextareaAutoresizeProps) { + return ( + + Label + + Some additional Info + Error Info + + ) +} diff --git a/packages/react/src/components/field/examples/TextareaControlled.tsx b/packages/react/src/components/field/examples/TextareaControlled.tsx new file mode 100644 index 0000000..dfd2374 --- /dev/null +++ b/packages/react/src/components/field/examples/TextareaControlled.tsx @@ -0,0 +1,20 @@ +import { useState } from 'react' +import { Field } from '../index' + +export interface TextareaControlledProps extends Field.RootProps {} + +export function TextareaControlled(props: TextareaControlledProps) { + const [value, setValue] = useState('This is some text\nthen more text') + + return ( + <> + Textarea value: {value} + + Label + setValue(e.target.value)} /> + Some additional Info + Error Info + + + ) +} diff --git a/packages/react/src/components/field/stories/field.stories.tsx b/packages/react/src/components/field/stories/field.stories.tsx index efc5050..f8bdec5 100644 --- a/packages/react/src/components/field/stories/field.stories.tsx +++ b/packages/react/src/components/field/stories/field.stories.tsx @@ -9,3 +9,12 @@ export default meta export { Basic } from '../examples/Basic' export { Disabled } from '../examples/Disabled' +export { Input } from '../examples/Input' +export { InputControlled } from '../examples/InputControlled' +export { ReactiveInvalid } from '../examples/ReactiveInvalid' +export { RequiredIndicator } from '../examples/RequiredIndicator' +export { Select } from '../examples/Select' +export { SelectControlled } from '../examples/SelectControlled' +export { Textarea } from '../examples/Textarea' +export { TextareaAutoresize } from '../examples/TextareaAutoresize' +export { TextareaControlled } from '../examples/TextareaControlled' diff --git a/packages/vue/src/components/field/stories/field.stories.ts b/packages/vue/src/components/field/stories/field.stories.ts index d73be7a..ab9021b 100644 --- a/packages/vue/src/components/field/stories/field.stories.ts +++ b/packages/vue/src/components/field/stories/field.stories.ts @@ -1,4 +1,14 @@ import Basic from '../examples/Basic.vue' +import Disabled from '../examples/Disabled.vue' +import Input from '../examples/Input.vue' +import InputControlled from '../examples/InputControlled.vue' +import ReactiveInvalid from '../examples/ReactiveInvalid.vue' +import RequiredIndicator from '../examples/RequiredIndicator.vue' +import Select from '../examples/Select.vue' +import SelectControlled from '../examples/SelectControlled.vue' +import Textarea from '../examples/Textarea.vue' +import TextareaAutoresize from '../examples/TextareaAutoresize.vue' +import TextareaControlled from '../examples/TextareaControlled.vue' export default { title: 'Components / Field', @@ -13,3 +23,73 @@ export function basic() { template: '', } } + +export function disabled() { + return { + components: { Disabled }, + template: '', + } +} + +export function input() { + return { + components: { Input }, + template: '', + } +} + +export function inputControlled() { + return { + components: { InputControlled }, + template: '', + } +} + +export function reactiveInvalid() { + return { + components: { ReactiveInvalid }, + template: '', + } +} + +export function requiredIndicator() { + return { + components: { RequiredIndicator }, + template: '', + } +} + +export function select() { + return { + components: { Select }, + template: '