Skip to content
Merged
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
2 changes: 1 addition & 1 deletion apps/docs/utils/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const components = {
// 'SfScrollable',
// 'SfSelect',
'SfSwitch',
// 'SfTextarea',
'SfTextarea',
// 'SfThumbnail',
// 'SfTooltip',
],
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/utils/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const hooks = [
// 'useDisclosure',
// 'useDropdown',
// 'useFocusVisible',
'useFocusVisible',
// 'usePagination',
// 'usePopover',
// 'useScrollable',
Expand Down
197 changes: 197 additions & 0 deletions apps/website/src/routes/examples/SfTextarea/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import { $, component$, useContext, useTask$ } from '@builder.io/qwik';
import { SfTextarea, SfTextareaSize } from 'qwik-storefront-ui';
import { ComponentExample } from '../../../components/utils/ComponentExample';
import { ControlsType } from '../../../components/utils/types';
import { EXAMPLES_STATE } from '../layout';

export default component$(() => {
const examplesState = useContext(EXAMPLES_STATE);

useTask$(() => {
examplesState.data = {
controls: [
{
type: 'select',
modelName: 'size',
propDefaultValue: 'SfInputSize.base',
propType: 'SfInputSize',
options: Object.keys(SfTextareaSize),
isRequired: false,
},
{
type: 'text',
propType: 'string',
modelName: 'label',
isRequired: false,
},
{
type: 'text',
propType: 'string',
modelName: 'placeholder',
isRequired: false,
},
{
type: 'text',
propType: 'string',
modelName: 'helpText',
isRequired: false,
},
{
type: 'text',
propType: 'string',
modelName: 'requiredText',
isRequired: false,
},
{
type: 'text',
propType: 'string',
modelName: 'errorText',
isRequired: false,
},
{
type: 'text',
propType: 'number',
modelName: 'characterLimit',
isRequired: false,
},
{
type: 'boolean',
propType: 'boolean',
modelName: 'disabled',
isRequired: false,
},
{
type: 'boolean',
propType: 'boolean',
modelName: 'required',
isRequired: false,
},
{
type: 'boolean',
propType: 'boolean',
modelName: 'invalid',
isRequired: false,
},
{
type: 'boolean',
propType: 'boolean',
modelName: 'readonly',
isRequired: false,
},
] satisfies ControlsType,
state: {
size: SfTextareaSize.base,
disabled: false,
required: false,
invalid: false,
readonly: undefined,
placeholder: 'Write something about yourself',
helpText: 'Do not include personal or financial information.',
requiredText: 'Required text',
errorText: 'Error message',
label: 'Description',
characterLimit: 12,
value: '',
},
};
});

const onInput = $((e: Event) => {
const target = e.target as HTMLInputElement;

examplesState.data.state = {
...examplesState.data.state,
value: target.value,
};
});

const isAboveLimit = examplesState.data.state.characterLimit
? examplesState.data.state.value.length >
examplesState.data.state.characterLimit
: false;

const charsCount = examplesState.data.state.characterLimit
? examplesState.data.state.characterLimit -
examplesState.data.state.value.length
: null;

const getCharacterLimitClass = () =>
isAboveLimit ? 'text-negative-700 font-medium' : 'text-neutral-500';

return (
<ComponentExample>
<label>
<span
class={[
'typography-text-sm font-medium',
{
'cursor-not-allowed text-disabled-500':
examplesState.data.state.disabled,
},
]}
>
{examplesState.data.state.label}
</span>
<SfTextarea
name={examplesState.data.state.label}
size={examplesState.data.state.size}
value={examplesState.data.state.value}
invalid={examplesState.data.state.invalid}
placeholder={examplesState.data.state.placeholder}
disabled={examplesState.data.state.disabled}
readOnly={examplesState.data.state.readonly}
onInput$={onInput}
wrapperClass={[
`w-full block h-2/5 ${
examplesState.data.state.disabled
? '!bg-disabled-100 !ring-disabled-300 !ring-1 !text-disabled-500'
: examplesState.data.state.readonly &&
'!bg-disabled-100 !ring-disabled-300 !ring-1 !text-neutral-500'
}`,
]}
/>
</label>
<div class="flex justify-between">
<div>
{examplesState.data.state.invalid &&
!examplesState.data.state.disabled && (
<p class="typography-error-sm text-negative-700 font-medium mt-0.5">
{examplesState.data.state.errorText}
</p>
)}
{examplesState.data.state.helpText && (
<p
class={[
'typography-hint-xs mt-0.5',
examplesState.data.state.disabled
? 'text-disabled-500'
: 'text-neutral-500',
]}
>
{examplesState.data.state.helpText}
</p>
)}
{examplesState.data.state.requiredText &&
examplesState.data.state.required ? (
<p class="mt-1 typography-text-sm font-normal text-neutral-500 before:content-['*']">
{examplesState.data.state.requiredText}
</p>
) : null}
</div>
{examplesState.data.state.characterLimit &&
!examplesState.data.state.readonly ? (
<p
class={[
'typography-error-xs mt-0.5',
examplesState.data.state.disabled
? 'text-disabled-500'
: getCharacterLimitClass(),
]}
>
{charsCount}
</p>
) : null}
</div>
</ComponentExample>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { component$, useSignal, useTask$ } from '@builder.io/qwik';
import { attach } from '@frsource/autoresize-textarea';
import { SfTextarea } from 'qwik-storefront-ui';

export default component$(() => {
const textareaRef = useSignal<HTMLTextAreaElement>();

useTask$(() => {
if (textareaRef.value) {
attach(textareaRef.value);
}
});
return (
<>
<label>
<span class="typography-text-sm font-medium">Description</span>
<SfTextarea
ref={textareaRef}
wrapperClass={['w-full h-max-[500px] block']}
size="sm"
aria-label="Label size sm"
/>
</label>
<p class="typography-hint-xs text-neutral-500 mt-0.5">
Do not include personal or financial information.
</p>
</>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { $, component$, useComputed$, useSignal } from '@builder.io/qwik';
import { SfTextarea } from 'qwik-storefront-ui';

export default component$(() => {
const characterLimit = 25;
const disabled = false;
const readonly = false;
const invalid = false;
const helpText = 'Help text';
const errorText = 'Error';

const valueSignal = useSignal('');

const isAboveLimitSignal = useComputed$(() =>
characterLimit ? valueSignal.value.length > characterLimit : false
);

const charsCountSignal = useComputed$(() =>
characterLimit ? characterLimit - valueSignal.value.length : null
);

const getCharacterLimitClass = () =>
isAboveLimitSignal.value
? 'text-negative-700 font-medium'
: 'text-neutral-500';

const onInput = $((e: Event) => {
const target = e.target as HTMLInputElement;
valueSignal.value = target.value;
});

return (
<>
<label>
<span class="text-sm font-medium">Description</span>
<SfTextarea
value={valueSignal.value}
placeholder="Write something about yourself..."
invalid={invalid}
disabled={disabled}
onInput$={onInput}
wrapperClass={['w-full mt-0.5 block']}
/>
</label>
<div class="flex justify-between mt-0.5">
<div>
{invalid && !disabled && (
<p class="typography-text-sm text-negative-700 font-medium mt-0.5">
{errorText}
</p>
)}
{helpText && (
<p
class={[
'typography-hint-xs',
disabled ? 'text-disabled-500' : 'text-neutral-500',
]}
>
{helpText}
</p>
)}
</div>
{characterLimit && !readonly ? (
<p
class={[
'typography-error-xs',
disabled ? 'text-disabled-500' : getCharacterLimitClass(),
]}
>
{charsCountSignal.value}
</p>
) : null}
</div>
</>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { component$ } from '@builder.io/qwik';
import { SfTextarea } from 'qwik-storefront-ui';

export default component$(() => {
return (
<>
<label>
<span class="typography-text-sm font-medium cursor-not-allowed text-disabled-900">
Description
</span>
<SfTextarea
disabled
placeholder="Write something about yourself..."
wrapperClass={[
'w-full !bg-disabled-100 !ring-disabled-300 !ring-1 block',
]}
/>
</label>
<p class="typography-hint-xs text-disabled-500 mt-0.5">
Do not include personal or financial information.
</p>
</>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { component$ } from '@builder.io/qwik';
import { SfTextarea } from 'qwik-storefront-ui';

export default component$(() => {
return (
<>
<label>
<span class="typography-text-sm font-medium">Description</span>
<SfTextarea
invalid
placeholder="Write something about yourself..."
wrapperClass={['w-full block']}
/>
</label>
<div class="flex justify-between mt-0.5">
<p class="typography-text-sm text-negative-700 font-medium">
The field cannot be empty
</p>
<p class="typography-hint-xs text-neutral-500">
Do not include personal or financial information.
</p>
</div>
</>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { component$ } from '@builder.io/qwik';
import { SfTextarea } from 'qwik-storefront-ui';

export default component$(() => {
return (
<>
<label>
<span class="typography-text-sm font-medium">Description</span>
<SfTextarea
value="Hello! I'm a passionate shopper and a regular user of this ecommerce platform."
wrapperClass={[
'w-full !bg-disabled-100 !ring-disabled-300 !ring-1 block',
]}
readOnly
/>
</label>
<p class="typography-hint-xs text-neutral-500 mt-0.5">
Do not include personal or financial information.
</p>
</>
);
});
Loading