CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-keystone-ui--core

Core design system components and utilities for KeystoneJS applications

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

state-management.mddocs/

State Management

Utility hooks and functions for managing component state, particularly in controlled/uncontrolled component patterns common in form elements and interactive components.

Capabilities

Managed State Hook

Hook for managing component state that can be either controlled (managed by parent) or uncontrolled (managed internally), with automatic detection and warnings for improper usage patterns.

/**
 * Hook for controlled/uncontrolled component state management
 * @param controlledValue - Value controlled by parent component
 * @param defaultValue - Default value for uncontrolled mode
 * @param onChange - Change handler function
 * @returns Tuple of current value and change handler
 */
function useManagedState<V, E = ChangeEvent>(
  controlledValue: V | undefined,
  defaultValue: V,
  onChange: ManagedChangeHandler<V, E> | undefined
): [V, ManagedChangeHandler<V, E>];

/**
 * Type for change handler functions
 */
type ManagedChangeHandler<V = string, E = ChangeEvent> = (value: V, event: E) => void;

Usage Examples:

import { useManagedState, ManagedChangeHandler } from "@keystone-ui/core";

// Custom input component supporting controlled and uncontrolled modes
interface CustomInputProps {
  value?: string;
  defaultValue?: string;
  onChange?: ManagedChangeHandler<string>;
  placeholder?: string;
}

function CustomInput({ 
  value: controlledValue, 
  defaultValue = '', 
  onChange,
  placeholder 
}: CustomInputProps) {
  const [value, setValue] = useManagedState(
    controlledValue,
    defaultValue,
    onChange
  );
  
  return (
    <input
      value={value}
      onChange={(e) => setValue(e.target.value, e)}
      placeholder={placeholder}
    />
  );
}

// Controlled usage
function ControlledExample() {
  const [inputValue, setInputValue] = useState('');
  
  return (
    <CustomInput
      value={inputValue}
      onChange={(value) => setInputValue(value)}
    />
  );
}

// Uncontrolled usage
function UncontrolledExample() {
  return (
    <CustomInput
      defaultValue="initial value"
      onChange={(value) => console.log('Changed to:', value)}
    />
  );
}

// Complex value types
interface ToggleProps {
  checked?: boolean;
  defaultChecked?: boolean;
  onChange?: ManagedChangeHandler<boolean, MouseEvent>;
}

function Toggle({ checked: controlledChecked, defaultChecked = false, onChange }: ToggleProps) {
  const [checked, setChecked] = useManagedState(
    controlledChecked,
    defaultChecked,
    onChange
  );
  
  return (
    <button
      role="switch"
      aria-checked={checked}
      onClick={(e) => setChecked(!checked, e)}
    >
      {checked ? 'On' : 'Off'}
    </button>
  );
}

Key Features:

  • Automatic Mode Detection: Detects controlled vs uncontrolled based on initial prop values
  • Development Warnings: Warns when components switch between controlled/uncontrolled modes
  • Type Safety: Full TypeScript support for value and event types
  • Flexible Events: Supports any event type, not just React ChangeEvents

Utility Functions

Development Warning Function

Development-only warning utility that logs messages to console when conditions are met, automatically disabled in production builds.

/**
 * Logs warning message in development mode only
 * @param condition - When true, the warning will be logged
 * @param message - Warning message to display
 */
function devWarning(condition: boolean, message: string): void;

Usage Examples:

import { devWarning } from "@keystone-ui/core";

function FormField({ required, value, onChange }) {
  // Warn about missing required props
  devWarning(
    required && !value,
    'FormField: required field is empty'
  );
  
  devWarning(
    value !== undefined && typeof onChange !== 'function',
    'FormField: controlled field is missing onChange handler'
  );
  
  // Warn about deprecated patterns
  devWarning(
    props.hasOwnProperty('color') && props.hasOwnProperty('variant'),
    'FormField: color prop is deprecated, use variant instead'
  );
  
  return <input value={value} onChange={onChange} required={required} />;
}

// Custom hook with validation warnings
function useFormValidation(schema, values) {
  devWarning(
    !schema,
    'useFormValidation: schema is required'
  );
  
  devWarning(
    Object.keys(values).length === 0,
    'useFormValidation: no values provided for validation'
  );
  
  // Validation logic...
}

ID Generation Utilities

Utilities for generating unique, accessible IDs with server-side rendering support and compound ID creation.

/**
 * Hook for generating unique IDs with SSR support
 * @param idFromProps - Optional ID provided via props
 * @returns Unique string ID or undefined during SSR
 */
function useId(idFromProps?: string | null): string | undefined;

/**
 * Creates compound ID from multiple inputs, filtering out null/undefined values
 * @param args - Values to combine into compound ID
 * @returns Compound ID string with components joined by '--'
 */
function makeId(...args: (string | number | null | undefined)[]): string;

Usage Examples:

import { useId, makeId } from "@keystone-ui/core";

// Form field with auto-generated IDs
function FormField({ 
  id: providedId, 
  label, 
  helperText, 
  errorMessage,
  required 
}) {
  const baseId = useId(providedId);
  const inputId = baseId;
  const labelId = makeId(baseId, 'label');
  const helperId = makeId(baseId, 'helper');
  const errorId = makeId(baseId, 'error');
  
  return (
    <div>
      <label id={labelId} htmlFor={inputId}>
        {label} {required && '*'}
      </label>
      
      <input
        id={inputId}
        aria-labelledby={labelId}
        aria-describedby={makeId(
          helperText && helperId,
          errorMessage && errorId
        )}
        aria-invalid={!!errorMessage}
        aria-required={required}
      />
      
      {helperText && (
        <div id={helperId} className="helper-text">
          {helperText}
        </div>
      )}
      
      {errorMessage && (
        <div id={errorId} className="error-text" role="alert">
          {errorMessage}
        </div>
      )}
    </div>
  );
}

// Modal with related IDs
function Modal({ titleId: providedTitleId, children }) {
  const baseId = useId();
  const titleId = useId(providedTitleId) || makeId(baseId, 'title');
  const contentId = makeId(baseId, 'content');
  
  return (
    <div
      role="dialog"
      aria-labelledby={titleId}
      aria-describedby={contentId}
    >
      <h2 id={titleId}>Modal Title</h2>
      <div id={contentId}>
        {children}
      </div>
    </div>
  );
}

// Compound IDs with filtering
makeId('modal', null, 'content');           // 'modal--content'
makeId('field', 123, undefined, 'input');   // 'field--123--input'
makeId(null, undefined);                    // ''

SSR-Safe Layout Effect Hook

Hook that provides SSR-safe useLayoutEffect functionality, automatically falling back to useEffect in server environments.

/**
 * SSR-safe version of useLayoutEffect
 * Falls back to no-op on server, useLayoutEffect on client
 */
const useSafeLayoutEffect: typeof useLayoutEffect;

Usage Examples:

import { useSafeLayoutEffect } from "@keystone-ui/core";

// Measuring DOM elements safely
function AutoResizeTextarea({ value, onChange }) {
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  
  useSafeLayoutEffect(() => {
    if (textareaRef.current) {
      // Reset height to get accurate scrollHeight
      textareaRef.current.style.height = 'auto';
      // Set height to content height
      textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
    }
  }, [value]);
  
  return (
    <textarea
      ref={textareaRef}
      value={value}
      onChange={onChange}
      style={{ resize: 'none', overflow: 'hidden' }}
    />
  );
}

// Focus management after render
function FocusOnMount({ autoFocus, children }) {
  const elementRef = useRef<HTMLElement>(null);
  
  useSafeLayoutEffect(() => {
    if (autoFocus && elementRef.current) {
      elementRef.current.focus();
    }
  }, [autoFocus]);
  
  return React.cloneElement(children, { ref: elementRef });
}

Advanced State Management Patterns

Compound Component State

Using managed state for compound component patterns:

function TabsProvider({ selectedTab, defaultSelectedTab, onTabChange, children }) {
  const [activeTab, setActiveTab] = useManagedState(
    selectedTab,
    defaultSelectedTab || 0,
    onTabChange
  );
  
  const contextValue = {
    activeTab,
    setActiveTab,
    registerTab: useCallback((index) => {
      // Tab registration logic
    }, [])
  };
  
  return (
    <TabsContext.Provider value={contextValue}>
      {children}
    </TabsContext.Provider>
  );
}

function Tab({ index, children }) {
  const { activeTab, setActiveTab } = useContext(TabsContext);
  const id = useId();
  const panelId = makeId(id, 'panel');
  
  return (
    <button
      id={id}
      role="tab"
      aria-selected={activeTab === index}
      aria-controls={panelId}
      onClick={() => setActiveTab(index)}
    >
      {children}
    </button>
  );
}

Form State Management

Combining multiple managed state hooks for complex forms:

function useFormState(initialValues, validationSchema) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  const [touched, setTouched] = useState({});
  
  const createFieldProps = useCallback((name) => {
    const fieldId = useId();
    const errorId = makeId(fieldId, 'error');
    
    return {
      id: fieldId,
      value: values[name] || '',
      onChange: (value) => {
        setValues(prev => ({ ...prev, [name]: value }));
        // Validate on change...
      },
      onBlur: () => {
        setTouched(prev => ({ ...prev, [name]: true }));
        // Validate on blur...
      },
      'aria-invalid': !!(errors[name] && touched[name]),
      'aria-describedby': errors[name] && touched[name] ? errorId : undefined
    };
  }, [values, errors, touched]);
  
  return { values, errors, touched, createFieldProps };
}

Best Practices

State Management Guidelines

  1. Use useManagedState for dual-mode components that need to work both controlled and uncontrolled
  2. Provide meaningful default values to ensure consistent initial state
  3. Use development warnings to guide proper component usage
  4. Generate stable IDs for accessibility relationships
  5. Handle SSR properly with useSafeLayoutEffect for DOM measurements

Performance Considerations

  • useManagedState creates stable change handlers to prevent unnecessary re-renders
  • useId generates IDs only once per component instance
  • devWarning calls are automatically stripped from production builds
  • useSafeLayoutEffect avoids server/client mismatches

docs

core-wrapper.md

emotion-integration.md

index.md

layout-components.md

state-management.md

theme-system.md

typography-components.md

utility-components.md

tile.json