CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/npm-jupyterlab--ui-components

JupyterLab React-based UI components library providing icons, forms, buttons, and widgets for consistent interface development.

43%

Overall

Evaluation43%

1.59x

Agent success when using this tile

Overview
Eval results
Files

utilities.mddocs/

Utilities

Helper functions and utilities for styling, DOM manipulation, positioning, and React integration. These utilities provide common functionality needed when building JupyterLab applications and widgets.

Capabilities

CSS Class Utilities

Functions for managing and combining CSS class names in a clean, efficient way.

/**
 * Combine CSS class names, filtering out falsy values
 * @param classes - Array of class names, objects, or falsy values
 * @returns Single combined class string
 */
function classes(
  ...classes: (string | false | undefined | null | { [className: string]: any })[]
): string;

/**
 * Combine CSS class names removing duplicates
 * @param classes - Array of class names, objects, or falsy values  
 * @returns Single combined class string without duplicates
 */
function classesDedupe(
  ...classes: (string | false | undefined | null | { [className: string]: any })[]
): string;

Usage Examples:

import { classes, classesDedupe } from '@jupyterlab/ui-components';

// Basic class combination
const buttonClass = classes(
  'jp-Button',
  isActive && 'jp-mod-active',
  isDisabled && 'jp-mod-disabled',
  customClass
);

// Conditional classes with objects
const widgetClass = classes(
  'jp-Widget',
  {
    'jp-mod-hidden': !visible,
    'jp-mod-focused': hasFocus,
    'jp-mod-current': isCurrent
  },
  additionalClasses
);

// Remove duplicates when combining from multiple sources
const combinedClass = classesDedupe(
  baseClasses,
  themeClasses,
  stateClasses,
  userClasses
);

// Use in React components
function MyButton({ active, disabled, className }: ButtonProps) {
  return (
    <button 
      className={classes(
        'my-button',
        active && 'active',
        disabled && 'disabled',
        className
      )}
    >
      Click me
    </button>
  );
}

// Complex conditional styling
const iconClass = classes(
  'icon',
  size === 'small' && 'icon-small',
  size === 'large' && 'icon-large',
  {
    'icon-spin': spinning,
    'icon-disabled': !enabled,
    'icon-primary': variant === 'primary',
    'icon-secondary': variant === 'secondary'
  }
);

DOM Utilities

Functions for working with DOM elements and converting between DOM and React patterns.

/**
 * Convert DOM element attributes to React props
 * @param elem - DOM element to extract attributes from
 * @param options - Options for conversion
 * @returns Object with React-compatible props
 */
function getReactAttrs(
  elem: Element, 
  options?: { ignore?: string[] }
): { [key: string]: string | null };

/**
 * Find tree item element in DOM hierarchy
 * @param el - Element to start search from
 * @returns Tree item element or null if not found
 */
function getTreeItemElement(el: HTMLElement): HTMLElement | null;

Usage Examples:

import { getReactAttrs, getTreeItemElement } from '@jupyterlab/ui-components';

// Convert DOM element to React props
function domElementToReact(element: Element) {
  const props = getReactAttrs(element, {
    ignore: ['style', 'class'] // Ignore these attributes
  });
  
  return (
    <div {...props}>
      Converted from DOM element
    </div>
  );
}

// Handle tree interactions
function handleTreeClick(event: MouseEvent) {
  const target = event.target as HTMLElement;
  const treeItem = getTreeItemElement(target);
  
  if (treeItem) {
    const itemId = treeItem.dataset.itemId;
    console.log('Clicked tree item:', itemId);
    
    // Handle tree item selection
    selectTreeItem(itemId);
  }
}

// Widget that uses DOM utilities
class InteractiveWidget extends Widget {
  onAfterAttach() {
    super.onAfterAttach();
    
    // Set up tree interaction handlers
    this.node.addEventListener('click', (event) => {
      const treeItem = getTreeItemElement(event.target as HTMLElement);
      if (treeItem) {
        this.handleTreeItemClick(treeItem);
      }
    });
  }
  
  private handleTreeItemClick(element: HTMLElement) {
    // Convert DOM attributes to work with
    const attrs = getReactAttrs(element);
    console.log('Tree item attributes:', attrs);
  }
}

// Extract data attributes
function extractDataAttributes(element: Element) {
  const attrs = getReactAttrs(element);
  const dataAttrs: { [key: string]: string } = {};
  
  Object.entries(attrs).forEach(([key, value]) => {
    if (key.startsWith('data-') && value !== null) {
      dataAttrs[key] = value;
    }
  });
  
  return dataAttrs;
}

HoverBox Positioning

Utility for positioning hover elements and tooltips relative to anchor elements.

/**
 * HoverBox positioning utilities
 */
type OutOfViewDisplay = 'hidden-inside' | 'hidden-outside' | 'stick-inside' | 'stick-outside';

namespace HoverBox {
  interface IOptions {
    /** Anchor element or position to attach to */
    anchor: IAnchor;
    /** Host element that contains the positioned element */
    host: HTMLElement;
    /** Maximum height for the positioned element */
    maxHeight: number;
    /** Minimum height for the positioned element */
    minHeight: number;
    /** Element to be positioned */
    node: HTMLElement;
    /** Positioning offsets */
    offset?: {
      horizontal?: number;
      vertical?: { above?: number; below?: number };
    };
    /** Vertical positioning preference */
    privilege?: 'above' | 'below' | 'forceAbove' | 'forceBelow';
    /** Custom style overrides */
    style?: CSSStyleDeclaration;
    /** Behavior when element goes out of view */
    outOfViewDisplay?: {
      top?: OutOfViewDisplay;
      bottom?: OutOfViewDisplay;
      left?: OutOfViewDisplay;
      right?: OutOfViewDisplay;
    };
    /** Fixed size for the element */
    size?: { width: number; height: number; };
  }
  
  /** Anchor position interface */
  interface IAnchor extends Pick<DOMRect, 'left' | 'right' | 'top' | 'bottom'> {}
  
  /**
   * Set geometry for positioned element
   * @param options - Positioning configuration
   */
  function setGeometry(options: IOptions): void;
}

Usage Examples:

import { HoverBox } from '@jupyterlab/ui-components';

// Create tooltip positioning
function createTooltip(anchorElement: HTMLElement, content: string) {
  const tooltip = document.createElement('div');
  tooltip.className = 'tooltip';
  tooltip.textContent = content;
  tooltip.style.position = 'absolute';
  tooltip.style.zIndex = '1000';
  
  document.body.appendChild(tooltip);
  
  // Position tooltip relative to anchor
  const anchorRect = anchorElement.getBoundingClientRect();
  
  HoverBox.setGeometry({
    anchor: {
      left: anchorRect.left,
      right: anchorRect.right,
      top: anchorRect.top,
      bottom: anchorRect.bottom
    },
    host: document.body,
    node: tooltip,
    maxHeight: 200,
    minHeight: 20,
    privilege: 'above',
    offset: {
      vertical: { above: 5, below: 5 },
      horizontal: 0
    }
  });
  
  return tooltip;
}

// Advanced positioning for dropdown
class DropdownWidget extends Widget {
  private _dropdown: HTMLElement;
  
  constructor() {
    super();
    this._dropdown = this.createDropdown();
  }
  
  showDropdown() {
    const buttonRect = this.node.getBoundingClientRect();
    
    HoverBox.setGeometry({
      anchor: {
        left: buttonRect.left,
        right: buttonRect.right,
        top: buttonRect.top,
        bottom: buttonRect.bottom
      },
      host: document.body,
      node: this._dropdown,
      maxHeight: 300,
      minHeight: 50,
      privilege: 'below',
      offset: {
        vertical: { below: 2 }
      },
      outOfViewDisplay: {
        bottom: 'stick',
        top: 'stick'
      }
    });
    
    this._dropdown.style.display = 'block';
  }
  
  hideDropdown() {
    this._dropdown.style.display = 'none';
  }
  
  private createDropdown(): HTMLElement {
    const dropdown = document.createElement('div');
    dropdown.className = 'dropdown-menu';
    dropdown.style.position = 'absolute';
    dropdown.style.display = 'none';
    dropdown.style.zIndex = '1000';
    
    document.body.appendChild(dropdown);
    return dropdown;
  }
}

// Context menu positioning
function showContextMenu(event: MouseEvent, items: MenuItem[]) {
  const menu = document.createElement('div');
  menu.className = 'context-menu';
  
  items.forEach(item => {
    const menuItem = document.createElement('div');
    menuItem.className = 'context-menu-item';
    menuItem.textContent = item.label;
    menuItem.onclick = item.action;
    menu.appendChild(menuItem);
  });
  
  document.body.appendChild(menu);
  
  // Position at mouse location
  HoverBox.setGeometry({
    anchor: {
      left: event.clientX,
      right: event.clientX,
      top: event.clientY,
      bottom: event.clientY
    },
    host: document.body,
    node: menu,
    maxHeight: 400,
    minHeight: 30,
    privilege: 'below',
    outOfViewDisplay: {
      right: 'stick',
      bottom: 'stick'
    }
  });
}

Element Reference Utilities

Interface for managing element references in React components.

/**
 * Interface for element reference properties
 */
interface IElementRefProps<E extends HTMLElement> {
  /** Callback function to receive element reference */
  elementRef?: (ref: E | null) => void;
}

/**
 * Default style class constant
 */
const DEFAULT_STYLE_CLASS = 'jp-DefaultStyle';

Usage Examples:

import { IElementRefProps, DEFAULT_STYLE_CLASS } from '@jupyterlab/ui-components';

// Component with element reference
interface CustomInputProps extends IElementRefProps<HTMLInputElement> {
  placeholder?: string;
  value?: string;
  onChange?: (value: string) => void;
}

function CustomInput({ elementRef, placeholder, value, onChange }: CustomInputProps) {
  const handleRef = (element: HTMLInputElement | null) => {
    if (element) {
      element.classList.add(DEFAULT_STYLE_CLASS);
    }
    elementRef?.(element);
  };
  
  return (
    <input
      ref={handleRef}
      placeholder={placeholder}
      value={value}
      onChange={(e) => onChange?.(e.target.value)}
      className="custom-input"
    />
  );
}

// Use with element reference
function ParentComponent() {
  const [inputElement, setInputElement] = useState<HTMLInputElement | null>(null);
  
  const focusInput = () => {
    inputElement?.focus();
  };
  
  return (
    <div>
      <CustomInput
        elementRef={setInputElement}
        placeholder="Enter text..."
      />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

// Widget that uses element references
class FormWidget extends ReactWidget {
  private _formElement: HTMLFormElement | null = null;
  
  protected render() {
    return (
      <form
        ref={(el) => this._formElement = el}
        className={DEFAULT_STYLE_CLASS}
      >
        <CustomInput
          elementRef={(el) => console.log('Input element:', el)}
          placeholder="Widget input"
        />
      </form>
    );
  }
  
  submitForm() {
    if (this._formElement) {
      this._formElement.requestSubmit();
    }
  }
}

// Generic element ref hook pattern
function useElementRef<T extends HTMLElement>() {
  const [element, setElement] = useState<T | null>(null);
  
  const ref = useCallback((el: T | null) => {
    if (el) {
      el.classList.add(DEFAULT_STYLE_CLASS);
    }
    setElement(el);
  }, []);
  
  return [element, ref] as const;
}

Node Styling Utilities

Utilities for applying consistent styling to DOM elements and their children.

/**
 * Namespace for DOM node styling utilities
 */
namespace Styling {
  /**
   * Style a node and its child elements with default tag names
   * @param node - Base DOM element to style 
   * @param className - Optional CSS class to add to styled nodes
   */
  function styleNode(node: HTMLElement, className?: string): void;
  
  /**
   * Style a node and elements with a specific tag name
   * @param node - Base DOM element to style
   * @param tagName - HTML tag name to target for styling
   * @param className - Optional CSS class to add to styled nodes  
   */
  function styleNodeByTag(node: HTMLElement, tagName: string, className?: string): void;
  
  /**
   * Wrap select elements with custom styling container
   * @param select - Select element to wrap
   * @param multiple - Whether select allows multiple selections
   */
  function wrapSelect(select: HTMLSelectElement, multiple?: boolean): void;
}

Usage Examples:

import { Styling } from '@jupyterlab/ui-components';

// Style all form elements in a container
function styleFormContainer(container: HTMLElement) {
  // Apply default styling to common form elements
  Styling.styleNode(container, 'custom-form-style');
  
  // This will add 'jp-mod-styled' class to all:
  // - select elements
  // - textarea elements  
  // - input elements
  // - button elements
}

// Style specific element types
function styleSpecificElements(container: HTMLElement) {
  // Style only input elements
  Styling.styleNodeByTag(container, 'input', 'styled-input');
  
  // Style only buttons
  Styling.styleNodeByTag(container, 'button', 'styled-button');
  
  // Style textareas with special class
  Styling.styleNodeByTag(container, 'textarea', 'styled-textarea');
}

// Widget that applies styling on render
class StyledFormWidget extends Widget {
  onAfterAttach() {
    super.onAfterAttach();
    
    // Apply JupyterLab styling to all form elements
    Styling.styleNode(this.node);
  }
  
  addFormField(fieldType: string, className?: string) {
    const field = document.createElement(fieldType);
    this.node.appendChild(field);
    
    // Style the new field specifically
    Styling.styleNodeByTag(this.node, fieldType, className);
  }
}

// Custom select wrapper usage
function createStyledSelect(options: string[], multiple = false) {
  const select = document.createElement('select');
  select.multiple = multiple;
  
  options.forEach(option => {
    const optionElement = document.createElement('option');
    optionElement.value = option;
    optionElement.textContent = option;
    select.appendChild(optionElement);
  });
  
  // Wrap with custom styling - handled automatically by styleNode
  const container = document.createElement('div');
  container.appendChild(select);
  Styling.styleNode(container);
  
  return container;
}

// Apply styling to dynamically created content
function createStyledDialog(content: HTMLElement) {
  const dialog = document.createElement('div');
  dialog.className = 'dialog-container';
  dialog.appendChild(content);
  
  // Ensure all form controls are properly styled
  Styling.styleNode(dialog, 'dialog-form');
  
  return dialog;
}

// Utility for styling imported HTML content
function styleImportedContent(htmlContent: string) {
  const container = document.createElement('div');
  container.innerHTML = htmlContent;
  
  // Style all form elements in the imported content
  Styling.styleNode(container);
  
  return container;
}

Type Definitions and Constants

Additional type definitions and constants used throughout the utilities.

// SVG type definitions (from svg.d.ts)
declare module '*.svg' {
  const value: string;
  export default value;
}

// React render element type
type ReactRenderElement = React.ReactElement<any> | null;

// Common interfaces and types used across utilities
interface IChangedArgs<T, U, K extends string> {
  name: K;
  oldValue: T;
  newValue: U;
}

Usage Examples:

// Import SVG files as strings
import iconSvg from './my-icon.svg';

// Create LabIcon from imported SVG
const myIcon = new LabIcon({
  name: 'my-app:my-icon',
  svgstr: iconSvg
});

// Use changed args in signals
class CounterModel extends VDomModel {
  private _count = 0;
  
  get count(): number {
    return this._count;
  }
  
  set count(value: number) {
    const oldValue = this._count;
    this._count = value;
    
    // Emit change signal with typed args
    this.stateChanged.emit({
      name: 'count',
      oldValue,
      newValue: value
    } as IChangedArgs<number, number, 'count'>);
  }
}

// Utility functions that work with React elements
function isValidRenderElement(element: any): element is ReactRenderElement {
  return element === null || React.isValidElement(element);
}

function renderIfValid(element: ReactRenderElement) {
  if (isValidRenderElement(element)) {
    return ReactDOM.render(element, container);
  }
  return null;
}
tessl i tessl/npm-jupyterlab--ui-components@4.4.0

docs

advanced-widgets.md

components.md

forms.md

icons.md

index.md

toolbars.md

utilities.md

widgets.md

tile.json