Skip to content

Commit

Permalink
feat: Editable (#890)
Browse files Browse the repository at this point in the history
* chore(Editable): add scaffold

* feat(Editable): implement component and axe test

* fix(Editable): fix hidden condition and events

* feat(Editable): implement EditableArea

* docs(Editable): implement stories

* fix(Editable): add EditableArea to components

* feat(Editable): implement event handling behaviour

* feat(Editable): add readonly property

* docs(Editable): add variants to chromatic

* chore(Editable): add tests

* docs(Editable): generate prop docs

* fix(Editable): fix context referencing

* docs(Editable): add documentation for the editable field

* feat(Editable): add autoResize prop

* docs(Editable): generate docs

* chore(Editable): add test for autoResize

* docs(Editable): add variant to Chromatic story

* chore: change modelValue slot name

* docs: update example

* docs: run codegen

---------

Co-authored-by: zernonia <zernonia@gmail.com>
  • Loading branch information
epr3 and zernonia committed May 13, 2024
1 parent f0bd36b commit 362930e
Show file tree
Hide file tree
Showing 30 changed files with 1,336 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export default defineConfig({
{ text: `Date Range Picker ${BadgeHTML('Alpha')}`, link: '/components/date-range-picker' },
{ text: 'Dialog', link: '/components/dialog' },
{ text: 'Dropdown Menu', link: '/components/dropdown-menu' },
{ text: `Editable ${BadgeHTML('Alpha')}`, link: '/components/editable' },
{ text: 'Hover Card', link: '/components/hover-card' },
{ text: 'Label', link: '/components/label' },
{ text: `Listbox ${BadgeHTML('Alpha')}`, link: '/components/listbox' },
Expand Down
4 changes: 4 additions & 0 deletions docs/components/Demos.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import DateRangeFieldDemo from './demo/DateRangeField/tailwind/index.vue'
import DateRangePickerDemo from './demo/DateRangePicker/tailwind/index.vue'
import DialogDemo from './demo/Dialog/tailwind/index.vue'
import DropdownMenuDemo from './demo/DropdownMenu/tailwind/index.vue'
import EditableDemo from './demo/Editable/tailwind/index.vue'
import HoverCardDemo from './demo/HoverCard/tailwind/index.vue'
import LabelDemo from './demo/Label/tailwind/index.vue'
import MenubarDemo from './demo/Menubar/tailwind/index.vue'
Expand Down Expand Up @@ -88,6 +89,9 @@ import DemoContainer from './DemoContainer.vue'
<DemoContainer title="dropdown menu">
<DropdownMenuDemo />
</DemoContainer>
<DemoContainer title="editable">
<EditableDemo />
</DemoContainer>
<DemoContainer title="hover card">
<HoverCardDemo />
</DemoContainer>
Expand Down
27 changes: 27 additions & 0 deletions docs/components/demo/Editable/css/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script setup lang="ts">
import { EditableArea, EditableCancelTrigger, EditableEditTrigger, EditableInput, EditablePreview, EditableRoot, EditableSubmitTrigger } from 'radix-vue'
import './styles.css'
</script>

<template>
<div style="width: 250px;">
<EditableRoot v-slot="{ isEditing }" placeholder="Enter text..." class="EditableRoot" default-value="Click to edit 'Radix Vue'" auto-resize>
<EditableArea class="EditableArea">
<EditablePreview />
<EditableInput />
</EditableArea>
<EditableEditTrigger
v-if="!isEditing"
class="EditableTrigger"
/>
<div v-else class="EditableWrapper">
<EditableSubmitTrigger
class="EditableSubmitTrigger"
/>
<EditableCancelTrigger
class="EditableTrigger"
/>
</div>
</EditableRoot>
</div>
</template>
48 changes: 48 additions & 0 deletions docs/components/demo/Editable/css/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.EditableRoot {
display: flex;
flex-direction: column;
gap: 1rem;
}

.EditableArea {
color: var(--white);
width: 250px;
}

.EditableWrapper {
display: flex;
gap: 1rem;
}

.EditableSubmitTrigger {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 0.25rem;
font-weight: 500;
font-size: 0.9375rem;
padding: 0.9375rem 1.25rem;
height: 2.1875rem;
background-color: var(--grass8);
color: var(--white);
box-shadow: 0px 2px 1.25rem rgba(0, 0, 0, 0.07), 0px 2px 1.25rem rgba(0, 0, 0, 0.07);
outline: none;
transition: background-color 0.2s, box-shadow 0.2s;
}


.EditableTrigger {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 0.25rem;
font-weight: 500;
font-size: 0.9375rem;
padding: 0.9375rem 1.25rem;
height: 2.1875rem;
background-color: var(--white);
color: var(--grass11);
box-shadow: 0px 2px 1.25rem rgba(0, 0, 0, 0.07), 0px 2px 1.25rem rgba(0, 0, 0, 0.07);
outline: none;
transition: background-color 0.2s, box-shadow 0.2s;
}
26 changes: 26 additions & 0 deletions docs/components/demo/Editable/tailwind/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup lang="ts">
import { EditableArea, EditableCancelTrigger, EditableEditTrigger, EditableInput, EditablePreview, EditableRoot, EditableSubmitTrigger } from 'radix-vue'
</script>

<template>
<div class="w-[250px]">
<EditableRoot v-slot="{ isEditing }" default-value="Click to edit 'Radix Vue'" placeholder="Enter text..." class="flex flex-col gap-4" auto-resize>
<EditableArea class="text-white w-[250px]">
<EditablePreview />
<EditableInput class="w-full placeholder:text-white" />
</EditableArea>
<EditableEditTrigger
v-if="!isEditing"
class="w-max inline-flex items-center justify-center rounded font-medium text-[15px] px-[15px] leading-[35px] h-[35px] bg-white text-green11 shadow-[0_2px_10px] shadow-blackA7 outline-none hover:bg-mauve3 focus:shadow-[0_0_0_2px] focus:shadow-black"
/>
<div v-else class="flex gap-4">
<EditableSubmitTrigger
class="inline-flex items-center justify-center rounded font-medium text-[15px] px-[15px] leading-[35px] h-[35px] bg-white text-green11 shadow-[0_2px_10px] shadow-blackA7 outline-none hover:bg-mauve3 focus:shadow-[0_0_0_2px] focus:shadow-black"
/>
<EditableCancelTrigger
class="inline-flex items-center justify-center rounded font-medium text-[15px] px-[15px] leading-[35px] h-[35px] bg-red9 text-white shadow-[0_2px_10px] shadow-blackA7 outline-none hover:bg-red10 focus:shadow-[0_0_0_2px] focus:shadow-black"
/>
</div>
</EditableRoot>
</div>
</template>
17 changes: 17 additions & 0 deletions docs/components/demo/Editable/tailwind/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const { blackA, grass, green, red } = require('@radix-ui/colors')

/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./**/*.vue'],
theme: {
extend: {
colors: {
...blackA,
...grass,
...green,
...red
},
},
},
plugins: [],
}
181 changes: 181 additions & 0 deletions docs/content/components/editable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
---
title: Editable
description: Displays an input field used for editing a single line of text, rendering as static text on load.
name: editable
---

# Editable

<Badge>Alpha</Badge>

<Description>
Displays an input field used for editing a single line of text, rendering as static text on load. It transforms into a text input field when the edit interaction is triggered.
</Description>

<ComponentPreview name="Editable" />

## Features

<Highlights
:features="[
'Full keyboard navigation',
'Can be controlled or uncontrolled',
'Focus is fully managed'
]"
/>

## Installation

Install the component from your command line.

<InstallationTabs value="radix-vue" />

## Anatomy

Import all parts and piece them together.

```vue
<script setup>
import {
EditableArea,
EditableCancelTrigger,
EditableEditTrigger,
EditableInput,
EditablePreview,
EditableRoot,
EditableSubmitTrigger
} from 'radix-vue'
</script>
<template>
<EditableRoot>
<EditableArea>
<EditablePreview />
<EditableInput />
</EditableArea>
<EditableEditTrigger />
<EditableSubmitTrigger />
<EditableCancelTrigger />
</EditableRoot>
</template>
```

## API Reference

### Root

Contains all the parts of an editable component.

<!-- @include: @/meta/EditableRoot.md -->

### Area

Contains the text parts of an editable component.

<!-- @include: @/meta/EditableArea.md -->

<DataAttributesTable
:data="[
{
attribute: '[data-readonly]',
values: 'Present when readonly',
},
{
attribute: '[data-disabled]',
values: 'Present when disabled',
},
{
attribute: '[data-placeholder-shown]',
values: 'Present when preview is shown',
},
{
attribute: '[data-empty]',
values: 'Present when the input is empty',
},
{
attribute: '[data-focus]',
values: 'Present when the editable field is focused',
}
]"
/>

### Input

Contains the input of an editable component.

<!-- @include: @/meta/EditableInput.md -->

<DataAttributesTable
:data="[
{
attribute: '[data-readonly]',
values: 'Present when readonly',
},
{
attribute: '[data-disabled]',
values: 'Present when disabled',
}
]"
/>


### Preview

Contains the preview of the editable component.

<!-- @include: @/meta/EditablePreview.md -->

### Edit Trigger

Contains the edit trigger of the editable component.

<!-- @include: @/meta/EditableEditTrigger.md -->

### Submit Trigger

Contains the submit trigger of the editable component.

<!-- @include: @/meta/EditableSubmitTrigger.md -->

### Cancel Trigger

Contains the cancel trigger of the editable component.

<!-- @include: @/meta/EditableCancelTrigger.md -->


## Accessibility

### Keyboard Interactions

<KeyboardTable
:data="[
{
keys: ['Tab'],
description: `<span>When focus moves onto the editable field, switches into the editable mode if the <Code>activation-mode</Code> is set to focus.</span>`
},
{
keys: ['Space'],
description:`
<span>
If the <Code>submit-mode</Code> is set to <Code>enter</Code> or <Code>both</Code>, it submits the changes.
</span>
` ,
},
{
keys: ['Enter'],
description:`
<span>
If the <Code>submit-mode</Code> is set to <Code>enter</Code> or <Code>both</Code>, it submits the changes.
</span>
` ,
},
{
keys: ['Escape'],
description:
`
When the focus is on the editable field, it cancels the changes.
`
}
]"
/>
17 changes: 17 additions & 0 deletions docs/content/meta/EditableArea.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!-- This file was automatic generated. Do not edit it manually -->

<PropsTable :data="[
{
'name': 'as',
'description': '<p>The element or component this component should render as. Can be overwrite by <code>asChild</code></p>\n',
'type': 'AsTag | Component',
'required': false,
'default': '\'div\''
},
{
'name': 'asChild',
'description': '<p>Change the default rendered element for the one passed as a child, merging their props and behavior.</p>\n<p>Read our <a href=\'https://www.radix-vue.com/guides/composition.html\'>Composition</a> guide for more details.</p>\n',
'type': 'boolean',
'required': false
}
]" />
17 changes: 17 additions & 0 deletions docs/content/meta/EditableCancelTrigger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!-- This file was automatic generated. Do not edit it manually -->

<PropsTable :data="[
{
'name': 'as',
'description': '<p>The element or component this component should render as. Can be overwrite by <code>asChild</code></p>\n',
'type': 'AsTag | Component',
'required': false,
'default': '\'button\''
},
{
'name': 'asChild',
'description': '<p>Change the default rendered element for the one passed as a child, merging their props and behavior.</p>\n<p>Read our <a href=\'https://www.radix-vue.com/guides/composition.html\'>Composition</a> guide for more details.</p>\n',
'type': 'boolean',
'required': false
}
]" />
17 changes: 17 additions & 0 deletions docs/content/meta/EditableEditTrigger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!-- This file was automatic generated. Do not edit it manually -->

<PropsTable :data="[
{
'name': 'as',
'description': '<p>The element or component this component should render as. Can be overwrite by <code>asChild</code></p>\n',
'type': 'AsTag | Component',
'required': false,
'default': '\'button\''
},
{
'name': 'asChild',
'description': '<p>Change the default rendered element for the one passed as a child, merging their props and behavior.</p>\n<p>Read our <a href=\'https://www.radix-vue.com/guides/composition.html\'>Composition</a> guide for more details.</p>\n',
'type': 'boolean',
'required': false
}
]" />
11 changes: 11 additions & 0 deletions docs/content/meta/EditableInput.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- This file was automatic generated. Do not edit it manually -->

<PropsTable :data="[
{
'name': 'type',
'description': '<p>The type of the input</p>\n',
'type': '\'text\' | \'search\' | \'email\' | \'password\' | \'tel\' | \'url\'',
'required': false,
'default': '\'text\''
}
]" />

0 comments on commit 362930e

Please sign in to comment.