Compare commits
2 commits
cef242e173
...
770b6e84bb
Author | SHA1 | Date | |
---|---|---|---|
770b6e84bb | |||
a695b2bb7e |
3 changed files with 68 additions and 30 deletions
|
@ -62,11 +62,12 @@ table {
|
||||||
table th,
|
table th,
|
||||||
table td {
|
table td {
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
padding: var(--spacing-sm);
|
padding: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
table th {
|
table th {
|
||||||
|
@ -144,37 +145,33 @@ table th {
|
||||||
EDITABLE CELL STYLES
|
EDITABLE CELL STYLES
|
||||||
================================= */
|
================================= */
|
||||||
|
|
||||||
|
/* Spreadsheet-like cell styling */
|
||||||
.editable-cell {
|
.editable-cell {
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 2rem;
|
min-height: 2.5rem;
|
||||||
|
max-height: 12rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 0.5rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-cell input,
|
.editable-cell input,
|
||||||
.editable-cell textarea {
|
.editable-cell textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
background: transparent;
|
|
||||||
resize: none;
|
|
||||||
padding: var(--spacing-xs);
|
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
transition: all 0.2s ease-in-out;
|
color: inherit;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
resize: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-cell input:focus,
|
|
||||||
.editable-cell textarea:focus {
|
|
||||||
background-color: #fef3c7;
|
|
||||||
border: 2px solid var(--color-warning);
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.focused-cell {
|
|
||||||
background-color: #fef3c7 !important;
|
|
||||||
border: 2px solid var(--color-warning) !important;
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =================================
|
/* =================================
|
||||||
TYPEAHEAD STYLES
|
TYPEAHEAD STYLES
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
import React, { useState, useEffect, useCallback, useRef, useLayoutEffect } from 'react';
|
||||||
|
|
||||||
interface EditableCellProps {
|
interface EditableCellProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -63,6 +63,40 @@ export function EditableCell({
|
||||||
}
|
}
|
||||||
}, [focusedCell, cellKey, inputType]);
|
}, [focusedCell, cellKey, inputType]);
|
||||||
|
|
||||||
|
// Auto-resize textarea based on content
|
||||||
|
const autoResize = useCallback(() => {
|
||||||
|
if (inputType === 'textarea' && textareaRef.current) {
|
||||||
|
const textarea = textareaRef.current;
|
||||||
|
|
||||||
|
// Reset height to auto to get the correct scrollHeight
|
||||||
|
textarea.style.height = 'auto';
|
||||||
|
|
||||||
|
// Calculate the required height
|
||||||
|
const scrollHeight = textarea.scrollHeight;
|
||||||
|
const minHeight = 40; // 2.5rem = 40px
|
||||||
|
const maxHeight = 192; // 12rem = 192px
|
||||||
|
|
||||||
|
// Set height within bounds
|
||||||
|
const newHeight = Math.min(Math.max(scrollHeight, minHeight), maxHeight);
|
||||||
|
textarea.style.height = `${newHeight}px`;
|
||||||
|
|
||||||
|
// Enable scrolling if content exceeds max height
|
||||||
|
textarea.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden';
|
||||||
|
}
|
||||||
|
}, [inputType]);
|
||||||
|
|
||||||
|
// Auto-resize on content change
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
autoResize();
|
||||||
|
}, [localValue, autoResize]);
|
||||||
|
|
||||||
|
// Auto-resize on focus (in case content was updated externally)
|
||||||
|
useEffect(() => {
|
||||||
|
if (focusedCell === cellKey) {
|
||||||
|
autoResize();
|
||||||
|
}
|
||||||
|
}, [focusedCell, cellKey, autoResize]);
|
||||||
|
|
||||||
const handleInput = useCallback((e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
const handleInput = useCallback((e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
const newValue = e.target.value;
|
const newValue = e.target.value;
|
||||||
console.log('Input event for cell:', cellKey, newValue);
|
console.log('Input event for cell:', cellKey, newValue);
|
||||||
|
@ -102,8 +136,10 @@ export function EditableCell({
|
||||||
}, [inputType, commitInput, setFocusedCell, value]);
|
}, [inputType, commitInput, setFocusedCell, value]);
|
||||||
|
|
||||||
const baseClassName = `
|
const baseClassName = `
|
||||||
w-full px-2 py-1 border-none outline-none resize-none
|
w-full h-full bg-transparent text-inherit
|
||||||
focus:ring-2 focus:ring-blue-500 focus:ring-inset
|
border-none outline-none focus:outline-none resize-none
|
||||||
|
placeholder:text-gray-400 dark:placeholder:text-gray-500
|
||||||
|
leading-relaxed
|
||||||
${className}
|
${className}
|
||||||
`.trim();
|
`.trim();
|
||||||
|
|
||||||
|
@ -117,9 +153,15 @@ export function EditableCell({
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
|
onInput={autoResize}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
className={`${baseClassName} min-h-[2rem] max-h-32`}
|
className={baseClassName}
|
||||||
rows={1}
|
style={{
|
||||||
|
minHeight: '2.5rem',
|
||||||
|
resize: 'none',
|
||||||
|
overflow: 'hidden'
|
||||||
|
}}
|
||||||
|
rows={1} // Start with single row
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -331,10 +331,9 @@ export function TypeaheadInput({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const baseInputClassName = `
|
const baseInputClassName = `
|
||||||
w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg
|
w-full h-full bg-transparent text-inherit
|
||||||
bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100
|
border-none outline-none focus:outline-none
|
||||||
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
|
placeholder:text-gray-400 dark:placeholder:text-gray-500
|
||||||
transition-all duration-200 ease-in-out
|
|
||||||
${className}
|
${className}
|
||||||
`.trim();
|
`.trim();
|
||||||
|
|
||||||
|
@ -469,7 +468,7 @@ export function TypeaheadInput({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative w-full h-full flex items-center">
|
||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
type="text"
|
type="text"
|
||||||
|
|
Loading…
Add table
Reference in a new issue