mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 17:18:32 +02:00
Auto-expand URL bar height
This commit is contained in:
@@ -47,11 +47,11 @@ export const UrlBar = memo(function UrlBar({ id: requestId, url, method, classNa
|
|||||||
<form onSubmit={handleSubmit} className={classNames('url-bar', className)}>
|
<form onSubmit={handleSubmit} className={classNames('url-bar', className)}>
|
||||||
<Input
|
<Input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
size="sm"
|
size="auto"
|
||||||
hideLabel
|
hideLabel
|
||||||
useTemplating
|
useTemplating
|
||||||
contentType="url"
|
contentType="url"
|
||||||
className="px-0"
|
className="px-0 py-0.5"
|
||||||
name="url"
|
name="url"
|
||||||
label="Enter URL"
|
label="Enter URL"
|
||||||
forceUpdateKey={updateKey}
|
forceUpdateKey={updateKey}
|
||||||
@@ -63,7 +63,7 @@ export const UrlBar = memo(function UrlBar({ id: requestId, url, method, classNa
|
|||||||
<RequestMethodDropdown
|
<RequestMethodDropdown
|
||||||
method={method}
|
method={method}
|
||||||
onChange={handleMethodChange}
|
onChange={handleMethodChange}
|
||||||
className="mx-0.5 h-full my-1"
|
className="!h-auto mx-0.5 my-0.5"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightSlot={
|
rightSlot={
|
||||||
@@ -72,7 +72,7 @@ export const UrlBar = memo(function UrlBar({ id: requestId, url, method, classNa
|
|||||||
iconSize="sm"
|
iconSize="sm"
|
||||||
title="Send Request"
|
title="Send Request"
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-8 mr-0.5"
|
className="!h-auto w-8 mr-0.5 my-0.5"
|
||||||
icon={loading ? 'update' : 'paperPlane'}
|
icon={loading ? 'update' : 'paperPlane'}
|
||||||
spin={loading}
|
spin={loading}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,203 +1,210 @@
|
|||||||
.cm-wrapper {
|
.cm-wrapper {
|
||||||
@apply h-full overflow-hidden;
|
@apply h-full overflow-hidden;
|
||||||
|
|
||||||
|
.cm-editor {
|
||||||
|
@apply w-full block text-base;
|
||||||
|
|
||||||
|
* {
|
||||||
|
@apply cursor-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cm-focused {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-content {
|
||||||
|
@apply py-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-line {
|
||||||
|
@apply text-gray-800 pl-1 pr-1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-placeholder {
|
||||||
|
@apply text-placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-scroller {
|
||||||
|
/* Inherit line-height from outside */
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't show selection on blurred input */
|
||||||
|
.cm-selectionBackground {
|
||||||
|
@apply bg-transparent;
|
||||||
|
}
|
||||||
|
&.cm-focused .cm-selectionBackground {
|
||||||
|
@apply bg-selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style gutters */
|
||||||
|
.cm-gutters {
|
||||||
|
@apply border-0 text-gray-500/50;
|
||||||
|
|
||||||
|
.cm-gutterElement {
|
||||||
|
@apply cursor-default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-widget {
|
||||||
|
@apply text-xs text-gray-800 dark:text-gray-900 px-1 rounded cursor-default dark:shadow;
|
||||||
|
|
||||||
|
/* NOTE: Background and border are translucent so we can see text selection through it */
|
||||||
|
@apply bg-gray-300/40 border border-gray-300 border-opacity-40 hover:border-opacity-80;
|
||||||
|
|
||||||
|
/* Bring above on hover */
|
||||||
|
@apply hover:z-10 relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cm-singleline {
|
||||||
|
.cm-editor {
|
||||||
|
@apply w-full h-auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-scroller {
|
||||||
|
@apply font-mono text-[0.8rem] overflow-hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-line {
|
||||||
|
@apply px-2 overflow-hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cm-multiline {
|
||||||
|
&.cm-full-height {
|
||||||
|
@apply relative;
|
||||||
|
|
||||||
|
.cm-editor {
|
||||||
|
@apply inset-0 absolute;
|
||||||
|
position: absolute !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cm-editor {
|
.cm-editor {
|
||||||
@apply w-full block text-base;
|
@apply h-full;
|
||||||
|
|
||||||
* {
|
|
||||||
@apply cursor-text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.cm-focused {
|
|
||||||
outline: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-content {
|
|
||||||
@apply py-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-line {
|
|
||||||
@apply text-gray-800 pl-1 pr-1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-placeholder {
|
|
||||||
@apply text-placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-scroller {
|
|
||||||
/* Inherit line-height from outside */
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't show selection on blurred input */
|
|
||||||
.cm-selectionBackground {
|
|
||||||
@apply bg-transparent;
|
|
||||||
}
|
|
||||||
&.cm-focused .cm-selectionBackground {
|
|
||||||
@apply bg-selection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style gutters */
|
|
||||||
.cm-gutters {
|
|
||||||
@apply border-0 text-gray-500/50;
|
|
||||||
|
|
||||||
.cm-gutterElement {
|
|
||||||
@apply cursor-default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-widget {
|
|
||||||
@apply text-xs text-gray-800 dark:text-gray-900 px-1 rounded cursor-default dark:shadow;
|
|
||||||
|
|
||||||
/* NOTE: Background and border are translucent so we can see text selection through it */
|
|
||||||
@apply bg-gray-300/40 border border-gray-300 border-opacity-40 hover:border-opacity-80;
|
|
||||||
|
|
||||||
/* Bring above on hover */
|
|
||||||
@apply hover:z-10 relative;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cm-singleline {
|
.cm-scroller {
|
||||||
.cm-editor {
|
@apply font-mono text-[0.75rem];
|
||||||
@apply w-full h-auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-scroller {
|
/*
|
||||||
@apply font-mono text-[0.8rem] overflow-hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-line {
|
|
||||||
@apply px-2 overflow-hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.cm-multiline {
|
|
||||||
&.cm-full-height {
|
|
||||||
@apply relative;
|
|
||||||
|
|
||||||
.cm-editor {
|
|
||||||
@apply inset-0 absolute;
|
|
||||||
position: absolute !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-editor {
|
|
||||||
@apply h-full;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-scroller {
|
|
||||||
@apply font-mono text-[0.75rem];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Round corners or they'll stick out of the editor bounds of editor is rounded.
|
* Round corners or they'll stick out of the editor bounds of editor is rounded.
|
||||||
* Could potentially be pushed up from the editor like we do with bg color but this
|
* Could potentially be pushed up from the editor like we do with bg color but this
|
||||||
* is probably fine.
|
* is probably fine.
|
||||||
*/
|
*/
|
||||||
@apply rounded-lg;
|
@apply rounded-lg;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Obscure text for password fields */
|
/* Obscure text for password fields */
|
||||||
.cm-wrapper.cm-obscure-text .cm-line {
|
.cm-wrapper.cm-obscure-text .cm-line {
|
||||||
-webkit-text-security: disc;
|
-webkit-text-security: disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .cm-gutterElement {
|
.cm-editor .cm-gutterElement {
|
||||||
@apply flex items-center;
|
@apply flex items-center;
|
||||||
transition: color var(--transition-duration);
|
transition: color var(--transition-duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .fold-gutter-icon {
|
.cm-editor .fold-gutter-icon {
|
||||||
@apply pt-[0.25em] pl-[0.4em] px-[0.4em] h-4 cursor-pointer rounded;
|
@apply pt-[0.25em] pl-[0.4em] px-[0.4em] h-4 cursor-pointer rounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .fold-gutter-icon::after {
|
.cm-editor .fold-gutter-icon::after {
|
||||||
@apply block w-1.5 h-1.5 border-transparent -rotate-45
|
@apply block w-1.5 h-1.5 border-transparent -rotate-45
|
||||||
border-l border-b border-l-[currentColor] border-b-[currentColor] content-[''];
|
border-l border-b border-l-[currentColor] border-b-[currentColor] content-[''];
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .fold-gutter-icon[data-open] {
|
.cm-editor .fold-gutter-icon[data-open] {
|
||||||
@apply pt-[0.38em] pl-[0.3em];
|
@apply pt-[0.38em] pl-[0.3em];
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .fold-gutter-icon[data-open]::after {
|
.cm-editor .fold-gutter-icon[data-open]::after {
|
||||||
@apply rotate-[-135deg];
|
@apply rotate-[-135deg];
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .fold-gutter-icon:hover {
|
.cm-editor .fold-gutter-icon:hover {
|
||||||
@apply text-gray-900 bg-gray-300/50;
|
@apply text-gray-900 bg-gray-300/50;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .cm-foldPlaceholder {
|
.cm-editor .cm-foldPlaceholder {
|
||||||
@apply px-2 border border-gray-400/50 bg-gray-300/50 cursor-default;
|
@apply px-2 border border-gray-400/50 bg-gray-300/50 cursor-default;
|
||||||
@apply hover:text-gray-800 hover:border-gray-400;
|
@apply hover:text-gray-800 hover:border-gray-400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .cm-activeLineGutter {
|
.cm-editor .cm-activeLineGutter {
|
||||||
@apply bg-transparent;
|
@apply bg-transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-wrapper:not(.cm-readonly) .cm-editor {
|
.cm-wrapper:not(.cm-readonly) .cm-editor {
|
||||||
&.cm-focused .cm-activeLineGutter {
|
&.cm-focused .cm-activeLineGutter {
|
||||||
@apply text-gray-600;
|
@apply text-gray-600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-cursor {
|
.cm-cursor {
|
||||||
@apply border-l-2 border-gray-800;
|
@apply border-l-2 border-gray-800;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-singleline .cm-editor {
|
.cm-singleline .cm-editor {
|
||||||
.cm-content {
|
.cm-content {
|
||||||
@apply h-full flex items-center;
|
@apply h-full flex items-center;
|
||||||
|
|
||||||
|
/* Break characters on line wrapping mode, useful for URL field.
|
||||||
|
* We can make this dynamic if we need it to be configurable later
|
||||||
|
*/
|
||||||
|
&.cm-lineWrapping {
|
||||||
|
@apply break-all;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: Extra selector required to override default styles */
|
/* NOTE: Extra selector required to override default styles */
|
||||||
.cm-tooltip.cm-tooltip {
|
.cm-tooltip.cm-tooltip {
|
||||||
@apply shadow-lg bg-gray-50 rounded text-gray-700 border border-gray-200 z-50 pointer-events-auto text-[0.75rem];
|
@apply shadow-lg bg-gray-50 rounded text-gray-700 border border-gray-200 z-50 pointer-events-auto text-[0.75rem];
|
||||||
|
|
||||||
&.cm-completionInfo-right {
|
&.cm-completionInfo-right {
|
||||||
@apply ml-1 -mt-0.5 text-sm;
|
@apply ml-1 -mt-0.5 text-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cm-completionInfo-right-narrow {
|
||||||
|
@apply ml-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
@apply transition-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cm-tooltip-autocomplete {
|
||||||
|
& > ul {
|
||||||
|
@apply p-1 max-h-[40vh];
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cm-completionInfo-right-narrow {
|
& > ul > li {
|
||||||
@apply ml-1;
|
@apply cursor-default px-2 rounded-sm text-gray-600 h-7 flex items-center;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
& > ul > li[aria-selected] {
|
||||||
@apply transition-none;
|
@apply bg-highlight text-gray-900;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cm-tooltip-autocomplete {
|
.cm-completionIcon {
|
||||||
& > ul {
|
@apply text-sm flex items-center pb-0.5 flex-shrink-0;
|
||||||
@apply p-1 max-h-[40vh];
|
|
||||||
}
|
|
||||||
|
|
||||||
& > ul > li {
|
|
||||||
@apply cursor-default px-2 rounded-sm text-gray-600 h-7 flex items-center;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > ul > li[aria-selected] {
|
|
||||||
@apply bg-highlight text-gray-900;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-completionIcon {
|
|
||||||
@apply text-sm flex items-center pb-0.5 flex-shrink-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-completionLabel {
|
|
||||||
@apply text-gray-700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-completionDetail {
|
|
||||||
@apply ml-auto pl-6;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cm-completionLabel {
|
||||||
|
@apply text-gray-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-completionDetail {
|
||||||
|
@apply ml-auto pl-6;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add default icon. Needs low priority so it can be overwritten */
|
/* Add default icon. Needs low priority so it can be overwritten */
|
||||||
.cm-completionIcon::after {
|
.cm-completionIcon::after {
|
||||||
content: '𝑥';
|
content: '𝑥';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export interface EditorProps {
|
|||||||
onChange?: (value: string) => void;
|
onChange?: (value: string) => void;
|
||||||
onFocus?: () => void;
|
onFocus?: () => void;
|
||||||
onBlur?: () => void;
|
onBlur?: () => void;
|
||||||
onSubmit?: () => void;
|
onEnter?: () => void;
|
||||||
singleLine?: boolean;
|
singleLine?: boolean;
|
||||||
wrapLines?: boolean;
|
wrapLines?: boolean;
|
||||||
format?: (v: string) => string;
|
format?: (v: string) => string;
|
||||||
@@ -58,7 +58,7 @@ const _Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
|||||||
onChange,
|
onChange,
|
||||||
onFocus,
|
onFocus,
|
||||||
onBlur,
|
onBlur,
|
||||||
onSubmit,
|
onEnter,
|
||||||
className,
|
className,
|
||||||
singleLine,
|
singleLine,
|
||||||
format,
|
format,
|
||||||
@@ -80,10 +80,10 @@ const _Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
|||||||
}, [onChange]);
|
}, [onChange]);
|
||||||
|
|
||||||
// Use ref so we can update the onChange handler without re-initializing the editor
|
// Use ref so we can update the onChange handler without re-initializing the editor
|
||||||
const handleSubmit = useRef<EditorProps['onSubmit']>(onSubmit);
|
const handleEnter = useRef<EditorProps['onEnter']>(onEnter);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleSubmit.current = onSubmit;
|
handleEnter.current = onEnter;
|
||||||
}, [onSubmit]);
|
}, [onEnter]);
|
||||||
|
|
||||||
// Use ref so we can update the onChange handler without re-initializing the editor
|
// Use ref so we can update the onChange handler without re-initializing the editor
|
||||||
const handleFocus = useRef<EditorProps['onFocus']>(onFocus);
|
const handleFocus = useRef<EditorProps['onFocus']>(onFocus);
|
||||||
@@ -143,7 +143,12 @@ const _Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
|||||||
let view: EditorView;
|
let view: EditorView;
|
||||||
try {
|
try {
|
||||||
const languageCompartment = new Compartment();
|
const languageCompartment = new Compartment();
|
||||||
const langExt = getLanguageExtension({ contentType, useTemplating, autocomplete, environment });
|
const langExt = getLanguageExtension({
|
||||||
|
contentType,
|
||||||
|
useTemplating,
|
||||||
|
autocomplete,
|
||||||
|
environment,
|
||||||
|
});
|
||||||
|
|
||||||
const state = EditorState.create({
|
const state = EditorState.create({
|
||||||
doc: `${defaultValue ?? ''}`,
|
doc: `${defaultValue ?? ''}`,
|
||||||
@@ -155,7 +160,7 @@ const _Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
|||||||
container,
|
container,
|
||||||
readOnly,
|
readOnly,
|
||||||
singleLine,
|
singleLine,
|
||||||
onSubmit: handleSubmit,
|
onEnter: handleEnter,
|
||||||
onChange: handleChange,
|
onChange: handleChange,
|
||||||
onFocus: handleFocus,
|
onFocus: handleFocus,
|
||||||
onBlur: handleBlur,
|
onBlur: handleBlur,
|
||||||
@@ -228,13 +233,13 @@ function getExtensions({
|
|||||||
onChange,
|
onChange,
|
||||||
onFocus,
|
onFocus,
|
||||||
onBlur,
|
onBlur,
|
||||||
onSubmit,
|
onEnter,
|
||||||
}: Pick<EditorProps, 'singleLine' | 'readOnly'> & {
|
}: Pick<EditorProps, 'singleLine' | 'readOnly'> & {
|
||||||
container: HTMLDivElement | null;
|
container: HTMLDivElement | null;
|
||||||
onChange: MutableRefObject<EditorProps['onChange']>;
|
onChange: MutableRefObject<EditorProps['onChange']>;
|
||||||
onFocus: MutableRefObject<EditorProps['onFocus']>;
|
onFocus: MutableRefObject<EditorProps['onFocus']>;
|
||||||
onBlur: MutableRefObject<EditorProps['onBlur']>;
|
onBlur: MutableRefObject<EditorProps['onBlur']>;
|
||||||
onSubmit: MutableRefObject<EditorProps['onSubmit']>;
|
onEnter: MutableRefObject<EditorProps['onEnter']>;
|
||||||
}) {
|
}) {
|
||||||
// TODO: Ensure tooltips render inside the dialog if we are in one.
|
// TODO: Ensure tooltips render inside the dialog if we are in one.
|
||||||
const parent =
|
const parent =
|
||||||
@@ -253,19 +258,19 @@ function getExtensions({
|
|||||||
: []),
|
: []),
|
||||||
...(singleLine
|
...(singleLine
|
||||||
? [
|
? [
|
||||||
EditorView.domEventHandlers({
|
EditorView.domEventHandlers({
|
||||||
focus: (_, view) => {
|
focus: (_, view) => {
|
||||||
// select all text on focus, like a regular input does
|
// select all text on focus, like a regular input does
|
||||||
view.dispatch({ selection: { anchor: 0, head: view.state.doc.length } });
|
view.dispatch({ selection: { anchor: 0, head: view.state.doc.length } });
|
||||||
},
|
},
|
||||||
keydown: (e) => {
|
keydown: (e) => {
|
||||||
// Submit nearest form on enter if there is one
|
// Submit nearest form on enter if there is one
|
||||||
if (onSubmit != null && e.key === 'Enter') {
|
if (onEnter != null && e.key === 'Enter') {
|
||||||
onSubmit.current?.();
|
onEnter.current?.();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
|
||||||
// Handle onFocus
|
// Handle onFocus
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export type InputProps = Omit<HTMLAttributes<HTMLInputElement>, 'onChange' | 'on
|
|||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
leftSlot?: ReactNode;
|
leftSlot?: ReactNode;
|
||||||
rightSlot?: ReactNode;
|
rightSlot?: ReactNode;
|
||||||
size?: 'sm' | 'md';
|
size?: 'sm' | 'md' | 'auto';
|
||||||
className?: string;
|
className?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
autoFocus?: boolean;
|
autoFocus?: boolean;
|
||||||
@@ -31,24 +31,24 @@ export type InputProps = Omit<HTMLAttributes<HTMLInputElement>, 'onChange' | 'on
|
|||||||
|
|
||||||
export const Input = forwardRef<EditorView | undefined, InputProps>(function Input(
|
export const Input = forwardRef<EditorView | undefined, InputProps>(function Input(
|
||||||
{
|
{
|
||||||
label,
|
|
||||||
type = 'text',
|
|
||||||
hideLabel,
|
|
||||||
className,
|
className,
|
||||||
containerClassName,
|
containerClassName,
|
||||||
labelClassName,
|
|
||||||
onChange,
|
|
||||||
placeholder,
|
|
||||||
size = 'md',
|
|
||||||
name,
|
|
||||||
leftSlot,
|
|
||||||
rightSlot,
|
|
||||||
defaultValue,
|
defaultValue,
|
||||||
validate,
|
|
||||||
require,
|
|
||||||
onFocus,
|
|
||||||
onBlur,
|
|
||||||
forceUpdateKey,
|
forceUpdateKey,
|
||||||
|
hideLabel,
|
||||||
|
label,
|
||||||
|
labelClassName,
|
||||||
|
leftSlot,
|
||||||
|
name,
|
||||||
|
onBlur,
|
||||||
|
onChange,
|
||||||
|
onFocus,
|
||||||
|
placeholder,
|
||||||
|
require,
|
||||||
|
rightSlot,
|
||||||
|
size = 'md',
|
||||||
|
type = 'text',
|
||||||
|
validate,
|
||||||
...props
|
...props
|
||||||
}: InputProps,
|
}: InputProps,
|
||||||
ref,
|
ref,
|
||||||
@@ -70,10 +70,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
|
|||||||
const id = `input-${name}`;
|
const id = `input-${name}`;
|
||||||
const inputClassName = classNames(
|
const inputClassName = classNames(
|
||||||
className,
|
className,
|
||||||
'!bg-transparent min-w-0 h-full w-full focus:outline-none placeholder:text-placeholder',
|
'!bg-transparent min-w-0 h-auto w-full focus:outline-none placeholder:text-placeholder',
|
||||||
// Bump things over if the slots are occupied
|
|
||||||
leftSlot && 'pl-0.5 -ml-2',
|
|
||||||
rightSlot && 'pr-0.5 -mr-2',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const isValid = useMemo(() => {
|
const isValid = useMemo(() => {
|
||||||
@@ -92,7 +89,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
|
|||||||
|
|
||||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const handleSubmit = useCallback(() => {
|
const handleEnter = useCallback(() => {
|
||||||
const form = wrapperRef.current?.closest('form');
|
const form = wrapperRef.current?.closest('form');
|
||||||
if (!isValid || form == null) return;
|
if (!isValid || form == null) return;
|
||||||
|
|
||||||
@@ -112,7 +109,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
|
|||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
<HStack
|
<HStack
|
||||||
alignItems="center"
|
alignItems="stretch"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
containerClassName,
|
containerClassName,
|
||||||
'relative w-full rounded-md text-gray-900',
|
'relative w-full rounded-md text-gray-900',
|
||||||
@@ -121,24 +118,31 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
|
|||||||
!isValid && '!border-invalid',
|
!isValid && '!border-invalid',
|
||||||
size === 'md' && 'h-md leading-md',
|
size === 'md' && 'h-md leading-md',
|
||||||
size === 'sm' && 'h-sm leading-sm',
|
size === 'sm' && 'h-sm leading-sm',
|
||||||
|
size === 'auto' && '!min-h-sm',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{leftSlot}
|
{leftSlot}
|
||||||
<Editor
|
<HStack
|
||||||
ref={ref}
|
alignItems="center"
|
||||||
id={id}
|
className={classNames('w-full', leftSlot && 'pl-0.5 -ml-2', rightSlot && 'pr-0.5 -mr-2')}
|
||||||
singleLine
|
>
|
||||||
onSubmit={handleSubmit}
|
<Editor
|
||||||
type={type === 'password' && !obscured ? 'text' : type}
|
ref={ref}
|
||||||
defaultValue={defaultValue}
|
id={id}
|
||||||
forceUpdateKey={forceUpdateKey}
|
singleLine
|
||||||
placeholder={placeholder}
|
wrapLines={size === 'auto'}
|
||||||
onChange={handleChange}
|
onEnter={handleEnter}
|
||||||
className={inputClassName}
|
type={type === 'password' && !obscured ? 'text' : type}
|
||||||
onFocus={handleFocus}
|
defaultValue={defaultValue}
|
||||||
onBlur={handleBlur}
|
forceUpdateKey={forceUpdateKey}
|
||||||
{...props}
|
placeholder={placeholder}
|
||||||
/>
|
onChange={handleChange}
|
||||||
|
className={inputClassName}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</HStack>
|
||||||
{type === 'password' && (
|
{type === 'password' && (
|
||||||
<IconButton
|
<IconButton
|
||||||
title={obscured ? `Show ${label}` : `Obscure ${label}`}
|
title={obscured ? `Show ${label}` : `Obscure ${label}`}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export const VStack = forwardRef(function VStack(
|
|||||||
type BaseStackProps = HTMLAttributes<HTMLElement> & {
|
type BaseStackProps = HTMLAttributes<HTMLElement> & {
|
||||||
as?: ComponentType | 'ul' | 'form';
|
as?: ComponentType | 'ul' | 'form';
|
||||||
space?: keyof typeof gapClasses;
|
space?: keyof typeof gapClasses;
|
||||||
alignItems?: 'start' | 'center';
|
alignItems?: 'start' | 'center' | 'stretch';
|
||||||
justifyContent?: 'start' | 'center' | 'end' | 'between';
|
justifyContent?: 'start' | 'center' | 'end' | 'between';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,6 +74,7 @@ const BaseStack = forwardRef(function BaseStack(
|
|||||||
'flex',
|
'flex',
|
||||||
alignItems === 'center' && 'items-center',
|
alignItems === 'center' && 'items-center',
|
||||||
alignItems === 'start' && 'items-start',
|
alignItems === 'start' && 'items-start',
|
||||||
|
alignItems === 'stretch' && 'items-stretch',
|
||||||
justifyContent === 'start' && 'justify-start',
|
justifyContent === 'start' && 'justify-start',
|
||||||
justifyContent === 'center' && 'justify-center',
|
justifyContent === 'center' && 'justify-center',
|
||||||
justifyContent === 'end' && 'justify-end',
|
justifyContent === 'end' && 'justify-end',
|
||||||
|
|||||||
@@ -1,89 +1,89 @@
|
|||||||
const plugin = require('tailwindcss/plugin')
|
const plugin = require('tailwindcss/plugin');
|
||||||
|
|
||||||
|
const height = {
|
||||||
|
xs: '1.75rem',
|
||||||
|
sm: '2.0rem',
|
||||||
|
md: '2.5rem',
|
||||||
|
};
|
||||||
|
|
||||||
/** @type {import("tailwindcss").Config} */
|
/** @type {import("tailwindcss").Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
darkMode: ["class", "[data-appearance=\"dark\"]"],
|
darkMode: ['class', '[data-appearance="dark"]'],
|
||||||
content: [
|
content: ['./index.html', './src-web/**/*.{html,js,jsx,ts,tsx}'],
|
||||||
"./index.html",
|
|
||||||
"./src-web/**/*.{html,js,jsx,ts,tsx}"
|
|
||||||
],
|
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
opacity: {
|
opacity: {
|
||||||
"disabled": "0.3"
|
disabled: '0.3',
|
||||||
},
|
},
|
||||||
fontSize: {
|
fontSize: {
|
||||||
"xs": "0.8rem"
|
xs: '0.8rem',
|
||||||
},
|
|
||||||
height: {
|
|
||||||
"xs": "1.75rem",
|
|
||||||
"sm": "2.0rem",
|
|
||||||
"md": "2.5rem"
|
|
||||||
},
|
},
|
||||||
|
height,
|
||||||
|
minHeight: height,
|
||||||
lineHeight: {
|
lineHeight: {
|
||||||
// HACK: Minus 2 to account for borders inside inputs
|
// HACK: Minus 2 to account for borders inside inputs
|
||||||
"xs": "calc(1.75rem - 2px)",
|
xs: 'calc(1.75rem - 2px)',
|
||||||
"sm": "calc(2.0rem - 2px)",
|
sm: 'calc(2.0rem - 2px)',
|
||||||
"md": "calc(2.5rem - 2px)"
|
md: 'calc(2.5rem - 2px)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
"mono": ["JetBrains Mono", "Menlo", "monospace"],
|
mono: ['JetBrains Mono', 'Menlo', 'monospace'],
|
||||||
"sans": [
|
sans: [
|
||||||
"Inter",
|
'Inter',
|
||||||
"-apple-system",
|
'-apple-system',
|
||||||
"BlinkMacSystemFont",
|
'BlinkMacSystemFont',
|
||||||
"Segoe UI",
|
'Segoe UI',
|
||||||
"Roboto",
|
'Roboto',
|
||||||
"Oxygen-Sans",
|
'Oxygen-Sans',
|
||||||
"Ubuntu",
|
'Ubuntu',
|
||||||
"Cantarell",
|
'Cantarell',
|
||||||
"Helvetica Neue",
|
'Helvetica Neue',
|
||||||
"sans-serif",
|
'sans-serif',
|
||||||
"Apple Color Emoji",
|
'Apple Color Emoji',
|
||||||
"Segoe UI Emoji",
|
'Segoe UI Emoji',
|
||||||
"Segoe UI Symbol",
|
'Segoe UI Symbol',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
fontSize: {
|
fontSize: {
|
||||||
'3xs': "0.6rem",
|
'3xs': '0.6rem',
|
||||||
'2xs': "0.7rem",
|
'2xs': '0.7rem',
|
||||||
xs: "0.8rem",
|
xs: '0.8rem',
|
||||||
sm: "0.9rem",
|
sm: '0.9rem',
|
||||||
base: "1rem",
|
base: '1rem',
|
||||||
xl: "1.25rem",
|
xl: '1.25rem',
|
||||||
"2xl": "1.563rem",
|
'2xl': '1.563rem',
|
||||||
"3xl": "1.953rem",
|
'3xl': '1.953rem',
|
||||||
"4xl": "2.441rem",
|
'4xl': '2.441rem',
|
||||||
"5xl": "3.052rem"
|
'5xl': '3.052rem',
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
selection: "hsl(var(--color-violet-500) / 0.4)",
|
selection: 'hsl(var(--color-violet-500) / 0.4)',
|
||||||
focus: "hsl(var(--color-blue-500) / 0.6)",
|
focus: 'hsl(var(--color-blue-500) / 0.6)',
|
||||||
invalid: "hsl(var(--color-red-500))",
|
invalid: 'hsl(var(--color-red-500))',
|
||||||
highlight: "hsl(var(--color-gray-300) / 0.35)",
|
highlight: 'hsl(var(--color-gray-300) / 0.35)',
|
||||||
highlightSecondary: "hsl(var(--color-gray-300) / 0.2)",
|
highlightSecondary: 'hsl(var(--color-gray-300) / 0.2)',
|
||||||
transparent: "transparent",
|
transparent: 'transparent',
|
||||||
white: "hsl(0 100% 100% / <alpha-value>)",
|
white: 'hsl(0 100% 100% / <alpha-value>)',
|
||||||
black: "hsl(0 100% 0% / <alpha-value>)",
|
black: 'hsl(0 100% 0% / <alpha-value>)',
|
||||||
placeholder: "hsl(var(--color-gray-400) / <alpha-value>)",
|
placeholder: 'hsl(var(--color-gray-400) / <alpha-value>)',
|
||||||
red: color("red"),
|
red: color('red'),
|
||||||
orange: color("orange"),
|
orange: color('orange'),
|
||||||
yellow: color("yellow"),
|
yellow: color('yellow'),
|
||||||
gray: color("gray"),
|
gray: color('gray'),
|
||||||
blue: color("blue"),
|
blue: color('blue'),
|
||||||
green: color("green"),
|
green: color('green'),
|
||||||
pink: color("pink"),
|
pink: color('pink'),
|
||||||
violet: color("violet")
|
violet: color('violet'),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
require("@tailwindcss/container-queries"),
|
require('@tailwindcss/container-queries'),
|
||||||
plugin(function({ addVariant }) {
|
plugin(function ({ addVariant }) {
|
||||||
addVariant('hocus', ['&:hover', '&:focus-visible', '&.focus:focus'])
|
addVariant('hocus', ['&:hover', '&:focus-visible', '&.focus:focus']);
|
||||||
addVariant('focus-visible-or-class', ['&:focus-visible', '&.focus:focus'])
|
addVariant('focus-visible-or-class', ['&:focus-visible', '&.focus:focus']);
|
||||||
})
|
}),
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
function color(name) {
|
function color(name) {
|
||||||
@@ -100,6 +100,6 @@ function color(name) {
|
|||||||
800: `hsl(var(--color-${name}-800) / <alpha-value>)`,
|
800: `hsl(var(--color-${name}-800) / <alpha-value>)`,
|
||||||
900: `hsl(var(--color-${name}-900) / <alpha-value>)`,
|
900: `hsl(var(--color-${name}-900) / <alpha-value>)`,
|
||||||
950: `hsl(var(--color-${name}-950) / <alpha-value>)`,
|
950: `hsl(var(--color-${name}-950) / <alpha-value>)`,
|
||||||
1000: `hsl(var(--color-${name}-1000) / <alpha-value>)`
|
1000: `hsl(var(--color-${name}-1000) / <alpha-value>)`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user