Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/storybook/src/stories/field.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ScoutInput,
ScoutSelect,
ScoutSwitch,
ScoutTextArea,
} from "@scouterna/ui-react";
import preview from "#.storybook/preview";

Expand All @@ -25,6 +26,17 @@ export const WithInput = meta.story({
),
});

export const WithTextArea = meta.story({
args: {
label: "Name",
},
render: (args) => (
<ScoutField {...args}>
<ScoutTextArea />
</ScoutField>
),
});

export const WithFieldTypeValidation = WithInput.extend({
args: {
helpText: "This field must contain a valid email address.",
Expand Down
25 changes: 25 additions & 0 deletions packages/storybook/src/stories/text-area.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ScoutTextArea } from "@scouterna/ui-react";
import preview from "#.storybook/preview";

const meta = preview.meta({
title: "Interaction/Text-Area",
component: ScoutTextArea,
parameters: {
layout: "centered",
},
});

export default meta;

export const BasicExample = meta.story({
args: {
name: "Name",
},
render: (args) => <ScoutTextArea {...args} />,
});

export const Disabled = BasicExample.extend({
args: {
disabled: true,
},
});
25 changes: 24 additions & 1 deletion packages/ui-react/lib/components/stencil-generated/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/* eslint-disable */

import { type ScoutCheckboxCustomEvent, type ScoutInputCustomEvent, type ScoutLinkCustomEvent, type ScoutSelectCustomEvent, type ScoutSwitchCustomEvent } from "@scouterna/ui-webc";
import { type ScoutCheckboxCustomEvent, type ScoutInputCustomEvent, type ScoutLinkCustomEvent, type ScoutSelectCustomEvent, type ScoutSwitchCustomEvent, type ScoutTextAreaCustomEvent } from "@scouterna/ui-webc";
import { ScoutBottomBarItem as ScoutBottomBarItemElement, defineCustomElement as defineScoutBottomBarItem } from "@scouterna/ui-webc/dist/components/scout-bottom-bar-item.js";
import { ScoutBottomBar as ScoutBottomBarElement, defineCustomElement as defineScoutBottomBar } from "@scouterna/ui-webc/dist/components/scout-bottom-bar.js";
import { ScoutButton as ScoutButtonElement, defineCustomElement as defineScoutButton } from "@scouterna/ui-webc/dist/components/scout-button.js";
Expand All @@ -24,6 +24,7 @@ import { ScoutLoader as ScoutLoaderElement, defineCustomElement as defineScoutLo
import { ScoutSelect as ScoutSelectElement, defineCustomElement as defineScoutSelect } from "@scouterna/ui-webc/dist/components/scout-select.js";
import { ScoutStack as ScoutStackElement, defineCustomElement as defineScoutStack } from "@scouterna/ui-webc/dist/components/scout-stack.js";
import { ScoutSwitch as ScoutSwitchElement, defineCustomElement as defineScoutSwitch } from "@scouterna/ui-webc/dist/components/scout-switch.js";
import { ScoutTextArea as ScoutTextAreaElement, defineCustomElement as defineScoutTextArea } from "@scouterna/ui-webc/dist/components/scout-text-area.js";
import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime';
import { createComponent } from '@stencil/react-output-target/runtime';
import React from 'react';
Expand Down Expand Up @@ -243,3 +244,25 @@ export const ScoutSwitch: StencilReactComponent<ScoutSwitchElement, ScoutSwitchE
} as ScoutSwitchEvents,
defineCustomElement: defineScoutSwitch
});

export type ScoutTextAreaEvents = {
onScoutInputChange: EventName<ScoutTextAreaCustomEvent<{
value: string;
element: HTMLInputElement;
}>>,
onScoutBlur: EventName<CustomEvent<void>>,
on_fieldId: EventName<CustomEvent<string>>
};

export const ScoutTextArea: StencilReactComponent<ScoutTextAreaElement, ScoutTextAreaEvents> = /*@__PURE__*/ createComponent<ScoutTextAreaElement, ScoutTextAreaEvents>({
tagName: 'scout-text-area',
elementClass: ScoutTextAreaElement,
// @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
react: React,
events: {
onScoutInputChange: 'scoutInputChange',
onScoutBlur: 'scoutBlur',
on_fieldId: '_fieldId'
} as ScoutTextAreaEvents,
defineCustomElement: defineScoutTextArea
});
84 changes: 84 additions & 0 deletions packages/ui-webc/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,29 @@ export namespace Components {
*/
"toggled": boolean;
}
interface ScoutTextArea {
/**
* @default false
*/
"autofocus": boolean;
"disabled"?: boolean;
"form": string;
"label"?: string;
"maxLength"?: number;
"name"?: string;
"placeholder"?: string;
"readOnly"?: boolean;
"required"?: boolean;
/**
* @default 3
*/
"rows"?: number;
/**
* Custom validation function run on top of the implicit validation performed by the browser. Return a string with the validation message to mark the input as invalid, or null to mark it as valid.
*/
"validate"?: (value: string) => string | null;
"value"?: string;
}
}
export interface ScoutBottomBarItemCustomEvent<T> extends CustomEvent<T> {
detail: T;
Expand Down Expand Up @@ -263,6 +286,10 @@ export interface ScoutSwitchCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLScoutSwitchElement;
}
export interface ScoutTextAreaCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLScoutTextAreaElement;
}
declare global {
/**
* The bottom bar component is used in the Jamboree26 app to provide
Expand Down Expand Up @@ -480,6 +507,28 @@ declare global {
prototype: HTMLScoutSwitchElement;
new (): HTMLScoutSwitchElement;
};
interface HTMLScoutTextAreaElementEventMap {
"scoutInputChange": {
value: string;
element: HTMLInputElement;
};
"scoutBlur": void;
"_fieldId": string;
}
interface HTMLScoutTextAreaElement extends Components.ScoutTextArea, HTMLStencilElement {
addEventListener<K extends keyof HTMLScoutTextAreaElementEventMap>(type: K, listener: (this: HTMLScoutTextAreaElement, ev: ScoutTextAreaCustomEvent<HTMLScoutTextAreaElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLScoutTextAreaElementEventMap>(type: K, listener: (this: HTMLScoutTextAreaElement, ev: ScoutTextAreaCustomEvent<HTMLScoutTextAreaElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLScoutTextAreaElement: {
prototype: HTMLScoutTextAreaElement;
new (): HTMLScoutTextAreaElement;
};
interface HTMLElementTagNameMap {
"scout-bottom-bar": HTMLScoutBottomBarElement;
"scout-bottom-bar-item": HTMLScoutBottomBarItemElement;
Expand All @@ -497,6 +546,7 @@ declare global {
"scout-select": HTMLScoutSelectElement;
"scout-stack": HTMLScoutStackElement;
"scout-switch": HTMLScoutSwitchElement;
"scout-text-area": HTMLScoutTextAreaElement;
}
}
declare namespace LocalJSX {
Expand Down Expand Up @@ -755,6 +805,38 @@ declare namespace LocalJSX {
*/
"toggled"?: boolean;
}
interface ScoutTextArea {
/**
* @default false
*/
"autofocus"?: boolean;
"disabled"?: boolean;
"form"?: string;
"label"?: string;
"maxLength"?: number;
"name"?: string;
"onScoutBlur"?: (event: ScoutTextAreaCustomEvent<void>) => void;
"onScoutInputChange"?: (event: ScoutTextAreaCustomEvent<{
value: string;
element: HTMLInputElement;
}>) => void;
/**
* Internal event used for form field association.
*/
"on_fieldId"?: (event: ScoutTextAreaCustomEvent<string>) => void;
"placeholder"?: string;
"readOnly"?: boolean;
"required"?: boolean;
/**
* @default 3
*/
"rows"?: number;
/**
* Custom validation function run on top of the implicit validation performed by the browser. Return a string with the validation message to mark the input as invalid, or null to mark it as valid.
*/
"validate"?: (value: string) => string | null;
"value"?: string;
}
interface IntrinsicElements {
"scout-bottom-bar": ScoutBottomBar;
"scout-bottom-bar-item": ScoutBottomBarItem;
Expand All @@ -772,6 +854,7 @@ declare namespace LocalJSX {
"scout-select": ScoutSelect;
"scout-stack": ScoutStack;
"scout-switch": ScoutSwitch;
"scout-text-area": ScoutTextArea;
}
}
export { LocalJSX as JSX };
Expand Down Expand Up @@ -808,6 +891,7 @@ declare module "@stencil/core" {
"scout-select": LocalJSX.ScoutSelect & JSXBase.HTMLAttributes<HTMLScoutSelectElement>;
"scout-stack": LocalJSX.ScoutStack & JSXBase.HTMLAttributes<HTMLScoutStackElement>;
"scout-switch": LocalJSX.ScoutSwitch & JSXBase.HTMLAttributes<HTMLScoutSwitchElement>;
"scout-text-area": LocalJSX.ScoutTextArea & JSXBase.HTMLAttributes<HTMLScoutTextAreaElement>;
}
}
}
35 changes: 35 additions & 0 deletions packages/ui-webc/src/components/text-area/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# scout-text-area

<!-- Auto Generated Below -->


## Properties

| Property | Attribute | Description | Type | Default |
| ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ----------- |
| `autofocus` | `autofocus` | | `boolean` | `false` |
| `disabled` | `disabled` | | `boolean` | `undefined` |
| `form` | `form` | | `string` | `undefined` |
| `label` | `label` | | `string` | `undefined` |
| `maxLength` | `max-length` | | `number` | `undefined` |
| `name` | `name` | | `string` | `undefined` |
| `placeholder` | `placeholder` | | `string` | `undefined` |
| `readOnly` | `read-only` | | `boolean` | `undefined` |
| `required` | `required` | | `boolean` | `undefined` |
| `rows` | `rows` | | `number` | `3` |
| `validate` | -- | Custom validation function run on top of the implicit validation performed by the browser. Return a string with the validation message to mark the input as invalid, or null to mark it as valid. | `(value: string) => string` | `undefined` |
| `value` | `value` | | `string` | `undefined` |


## Events

| Event | Description | Type |
| ------------------ | ----------------------------------------------- | ------------------------------------------------------------ |
| `_fieldId` | Internal event used for form field association. | `CustomEvent<string>` |
| `scoutBlur` | | `CustomEvent<void>` |
| `scoutInputChange` | | `CustomEvent<{ value: string; element: HTMLInputElement; }>` |


----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
15 changes: 15 additions & 0 deletions packages/ui-webc/src/components/text-area/text-area.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.textarea {
resize: none;
padding: var(--spacing-2);
font: var(--type-body-base);
border: 1px solid var(--color-gray-300);
border-radius: var(--spacing-2);
background-color: var(--color-white);
color: var(--color-text-base);
}

.textarea:disabled {
background-color: var(--color-gray-100);
color: var(--color-gray-700);
cursor: not-allowed;
}
94 changes: 94 additions & 0 deletions packages/ui-webc/src/components/text-area/text-area.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import {
Component,
Event,
type EventEmitter,
h,
Prop,
State,
} from "@stencil/core";

@Component({
tag: "scout-text-area",
styleUrl: "text-area.css",
scoped: true,
})
export class ScoutTextArea {
@Prop() name?: string;

@Prop() autofocus: boolean = false;

@Prop() disabled?: boolean;

@Prop() form: string;

@Prop() rows?: number = 3;

@Prop() maxLength?: number;

@Prop() placeholder?: string;

@Prop() readOnly?: boolean;

@Prop() required?: boolean;

@Prop() value?: string;

@Prop() label?: string;

/**
* Custom validation function run on top of the implicit validation performed
* by the browser. Return a string with the validation message to mark the
* input as invalid, or null to mark it as valid.
*/
@Prop() validate?: (value: string) => string | null;

@Event() scoutInputChange: EventEmitter<{
value: string;
element: HTMLInputElement;
}>;

@Event() scoutBlur: EventEmitter<void>;

/**
* Internal event used for form field association.
*/
@Event() _fieldId: EventEmitter<string>;

@State() ariaId: string;

componentWillLoad(): Promise<void> | void {
this.ariaId = `_${Math.random().toString(36).substring(2, 9)}`;
this._fieldId.emit(this.ariaId);
}

onInput(event: InputEvent) {
const input = event.target as HTMLInputElement;

if (this.validate) {
const validationMessage = this.validate(input.value);
input.setCustomValidity(validationMessage ?? "");
}

this.scoutInputChange.emit({
value: input.value,
element: input,
});
}
render() {
return (
<textarea
class="textarea"
name={this.name}
autofocus={this.autofocus}
disabled={this.disabled}
form={this.form}
rows={this.rows}
maxLength={this.maxLength}
placeholder={this.placeholder}
readOnly={this.readOnly}
required={this.required}
value={this.value}
/>
);
}
}