feat: TextInput/TextArea borderless+ariaLabel+onKeyDown, Alert info, иконка info (0.11.0)
Для инлайн-ячеек таблиц СТ и info-баннеров при перекраске форм. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tnsu/ui-kit",
|
"name": "@tnsu/ui-kit",
|
||||||
"version": "0.10.0",
|
"version": "0.11.0",
|
||||||
"description": "TNSU shared UI components for SPFx web parts",
|
"description": "TNSU shared UI components for SPFx web parts",
|
||||||
"author": "Timur Gorodetskiy",
|
"author": "Timur Gorodetskiy",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
|||||||
@@ -28,3 +28,9 @@
|
|||||||
color: $red-500;
|
color: $red-500;
|
||||||
border-color: #fecaca;
|
border-color: #fecaca;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
background: $navy-50;
|
||||||
|
color: $navy-800;
|
||||||
|
border-color: $navy-100;
|
||||||
|
}
|
||||||
|
|||||||
+5
-3
@@ -3,7 +3,7 @@ import styles from './Alert.module.scss';
|
|||||||
import { Icon } from '../Icon/Icon';
|
import { Icon } from '../Icon/Icon';
|
||||||
import { IconName } from '../Icon/iconNames';
|
import { IconName } from '../Icon/iconNames';
|
||||||
|
|
||||||
type AlertVariant = 'warn' | 'ok' | 'err';
|
type AlertVariant = 'warn' | 'ok' | 'err' | 'info';
|
||||||
|
|
||||||
interface IAlertProps {
|
interface IAlertProps {
|
||||||
variant: AlertVariant;
|
variant: AlertVariant;
|
||||||
@@ -13,13 +13,15 @@ interface IAlertProps {
|
|||||||
const variantClass: Record<AlertVariant, string> = {
|
const variantClass: Record<AlertVariant, string> = {
|
||||||
warn: styles.warn,
|
warn: styles.warn,
|
||||||
ok: styles.ok,
|
ok: styles.ok,
|
||||||
err: styles.err
|
err: styles.err,
|
||||||
|
info: styles.info
|
||||||
};
|
};
|
||||||
|
|
||||||
const variantIcon: Record<AlertVariant, IconName> = {
|
const variantIcon: Record<AlertVariant, IconName> = {
|
||||||
warn: 'warning',
|
warn: 'warning',
|
||||||
ok: 'check',
|
ok: 'check',
|
||||||
err: 'close'
|
err: 'close',
|
||||||
|
info: 'info'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Alert: React.FC<IAlertProps> = ({ variant, children }) => {
|
export const Alert: React.FC<IAlertProps> = ({ variant, children }) => {
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ export const IconSprite: React.FC = () => (
|
|||||||
<path d="M12 2 1 21h22z" strokeLinejoin="round" />
|
<path d="M12 2 1 21h22z" strokeLinejoin="round" />
|
||||||
<path d="M12 9v5M12 17h.01" />
|
<path d="M12 9v5M12 17h.01" />
|
||||||
</symbol>
|
</symbol>
|
||||||
|
<symbol id="i-info" viewBox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="9" />
|
||||||
|
<path d="M12 11v5M12 7.5h.01" />
|
||||||
|
</symbol>
|
||||||
<symbol id="i-check" viewBox="0 0 24 24">
|
<symbol id="i-check" viewBox="0 0 24 24">
|
||||||
<path d="M5 12l5 5L20 7" />
|
<path d="M5 12l5 5L20 7" />
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export const ICON_NAMES = [
|
|||||||
'search',
|
'search',
|
||||||
'menu',
|
'menu',
|
||||||
'warning',
|
'warning',
|
||||||
|
'info',
|
||||||
'check',
|
'check',
|
||||||
'plus'
|
'plus'
|
||||||
] as const;
|
] as const;
|
||||||
|
|||||||
@@ -21,3 +21,17 @@
|
|||||||
color: $gray-400;
|
color: $gray-400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Инлайн-ввод в ячейке таблицы: без рамки/фона, компактный, без ручного ресайза.
|
||||||
|
.borderless {
|
||||||
|
border-color: transparent;
|
||||||
|
background: transparent;
|
||||||
|
padding: 6px 8px;
|
||||||
|
min-height: 32px;
|
||||||
|
resize: none;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background: $white;
|
||||||
|
border-color: $gold-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,20 +10,25 @@ interface ITextAreaProps {
|
|||||||
rows?: number;
|
rows?: number;
|
||||||
/** Только чтение (режим согласующего). */
|
/** Только чтение (режим согласующего). */
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
/** Без рамки/фона — для инлайн-ввода в ячейках таблиц. */
|
||||||
|
borderless?: boolean;
|
||||||
|
/** a11y-подпись, когда видимого label нет. */
|
||||||
|
ariaLabel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Многострочный ввод (SharePoint Note). */
|
/** Многострочный ввод (SharePoint Note). */
|
||||||
export const TextArea: React.FC<ITextAreaProps> = ({ id, value, onChange, placeholder, rows = 3, readOnly }) => {
|
export const TextArea: React.FC<ITextAreaProps> = ({ id, value, onChange, placeholder, rows = 3, readOnly, borderless, ariaLabel }) => {
|
||||||
const contextReadOnly = useFormReadOnly();
|
const contextReadOnly = useFormReadOnly();
|
||||||
const effectiveReadOnly = readOnly ?? contextReadOnly;
|
const effectiveReadOnly = readOnly ?? contextReadOnly;
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
id={id}
|
id={id}
|
||||||
className={styles.textarea}
|
className={[styles.textarea, borderless ? styles.borderless : ''].filter(Boolean).join(' ')}
|
||||||
value={value}
|
value={value}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
rows={rows}
|
rows={rows}
|
||||||
readOnly={effectiveReadOnly}
|
readOnly={effectiveReadOnly}
|
||||||
|
aria-label={ariaLabel}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -19,3 +19,16 @@
|
|||||||
color: $gray-400;
|
color: $gray-400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Инлайн-ввод в ячейке таблицы: без рамки/фона, компактнее; рамка/фон проявляются на фокусе.
|
||||||
|
.borderless {
|
||||||
|
border-color: transparent;
|
||||||
|
background: transparent;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background: $white;
|
||||||
|
border-color: $gold-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ interface ITextInputProps {
|
|||||||
*/
|
*/
|
||||||
min?: string | number;
|
min?: string | number;
|
||||||
max?: string | number;
|
max?: string | number;
|
||||||
|
/** Без рамки/фона — для инлайн-ввода в ячейках таблиц (рамка проявляется на фокусе). */
|
||||||
|
borderless?: boolean;
|
||||||
|
/** a11y-подпись, когда видимого label нет (ячейки таблиц). */
|
||||||
|
ariaLabel?: string;
|
||||||
|
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
||||||
|
autoFocus?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Однострочный ввод. type='number'|'date' — для числовых полей и дат. */
|
/** Однострочный ввод. type='number'|'date' — для числовых полей и дат. */
|
||||||
@@ -30,20 +36,27 @@ export const TextInput: React.FC<ITextInputProps> = ({
|
|||||||
placeholder,
|
placeholder,
|
||||||
readOnly,
|
readOnly,
|
||||||
min,
|
min,
|
||||||
max
|
max,
|
||||||
|
borderless,
|
||||||
|
ariaLabel,
|
||||||
|
onKeyDown,
|
||||||
|
autoFocus
|
||||||
}) => {
|
}) => {
|
||||||
const contextReadOnly = useFormReadOnly();
|
const contextReadOnly = useFormReadOnly();
|
||||||
const effectiveReadOnly = readOnly ?? contextReadOnly;
|
const effectiveReadOnly = readOnly ?? contextReadOnly;
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
id={id}
|
id={id}
|
||||||
className={styles.input}
|
className={[styles.input, borderless ? styles.borderless : ''].filter(Boolean).join(' ')}
|
||||||
type={type}
|
type={type}
|
||||||
value={value}
|
value={value}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
readOnly={effectiveReadOnly}
|
readOnly={effectiveReadOnly}
|
||||||
|
aria-label={ariaLabel}
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
|
autoFocus={autoFocus}
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user