Skip to content

Responsive options ​

ResponsiveRenderOptions is the class behind an Action's breakpoints: it holds one set of options per breakpoint and resolves them into the set that applies at a given screen width. Action uses it for its render options. It is exported for subclasses; @dynamicforms/vuetify-modal-form-kit builds its form, row and column layouts on it.

Setting sm / md / lg on an action is documented in df-actions. This page documents writing a subclass.

How a breakpoint is resolved ​

Options are inherited from smaller breakpoints by larger ones. The options without a breakpoint apply to the smallest size, and each breakpoint sets only what differs from the one below it. Resolving md applies xs, sm and md in that order.

How a breakpoint's value applies depends on its kind:

ValueAt a breakpoint
undefined or nullnot set; the field keeps the inherited value
a single value (string, number, boolean, enum)replaces what it inherited
a plain objectis merged into what it inherited, key by key
anything else (an array, a Date, a Map, a class instance)replaces what it inherited
typescript
// base: { cols: 8, offset: 2 }, sm: { cols: 12 }
options.getOptionsForBreakpoint('sm'); // { cols: 12, offset: 2 } - offset carried over

The object merge is shallow: a nested object is replaced as a whole.

typescript
// base: { style: { color: 'red', margin: 10 } }, sm: { style: { color: 'blue' } }
options.getOptionsForBreakpoint('sm'); // { style: { color: 'blue' } } - margin is gone

Only plain objects merge. A Date, a Map, a Set or a class instance is replaced; merging it would produce a plain copy of its own properties without its prototype.

Writing a subclass ​

A subclass declares the shape of its options and implements cleanBreakpoint(), which normalizes the options of one breakpoint: it validates them and drops unsupported ones.

typescript
import { ResponsiveRenderOptions } from '@dynamicforms/vuetify-inputs';

interface PanelOptions {
  title?: string;
  props?: Record<string, any>;
  items?: string[];
}

class ResponsivePanelOptions extends ResponsiveRenderOptions<PanelOptions> {
  protected cleanBreakpoint(bp?: PanelOptions, defaultIfEmpty: boolean = false): PanelOptions | null {
    if (!bp && !defaultIfEmpty) return null;
    return {
      title: isString(bp?.title) ? bp.title : undefined,
      // a field the breakpoint does not state comes back undefined, never as an empty value
      props: bp?.props ? { ...bp.props } : undefined,
      items: bp?.items ? [...bp.items] : undefined,
    };
  }
}

cleanBreakpoint() returns undefined for a field the breakpoint does not set. An empty array or an empty string is a value and replaces the inherited one. A breakpoint clears a list with an empty array:

typescript
// base: { items: ['a', 'b'] }, md: { items: [] }
options.getOptionsForBreakpoint('sm'); // items: ['a', 'b']
options.getOptionsForBreakpoint('md'); // items: []

A class field initialized to a collection, e.g. items: string[] = [], sets an empty list on every breakpoint object, so every breakpoint clears the list instead of inheriting it. Such a field is declared optional and assigned when an item is added.

A field set only at md resolves from md upwards and is undefined below it.

typescript
// base: {}, md: { title: 'only at md' }
options.getOptionsForBreakpoint('sm'); // { }
options.getOptionsForBreakpoint('md'); // { title: 'only at md' }

Options forbidden in breakpoint declarations ​

ActionBreakpointOptions forbids setting the following options at a breakpoint:

  • name
  • defaultConfirm
  • defaultReject

These options identify the action and its role in the form, and that does not depend on screen width. They are set only on the base object. All other action options, including label and icon, may be set per breakpoint.

A subclass forbids options the same way: BreakpointsJSON takes a second type argument, the options a breakpoint may set. An option left out of it is a type error at a breakpoint.

typescript
interface PanelOptions {
  id?: string;
  title?: string;
}

type PanelBreakpointOptions = BreakpointsJSON<PanelOptions, Omit<PanelOptions, 'id'>>;

const ok: PanelBreakpointOptions = { id: 'main', title: 'Info', sm: { title: 'Order details' } };
const bad: PanelBreakpointOptions = { id: 'main', md: { id: 'wide' } };  // error: `id` is forbidden at a breakpoint

See also: df-actions, input base

Released under the MIT License.