ArcaneJaspr Codex
Documentation
ArcaneFlow
Auto-wrapping flex container for flowing layouts
Live Demo
Tag 1 Tag 2 Tag 3 Tag 4

ArcaneFlow#

A flex container that automatically wraps children when they exceed the container width, perfect for tags, chips, or responsive button groups.

Basic Usage#

ArcaneFlow(
  children: [
    ArcaneBadge(label: 'React'),
    ArcaneBadge(label: 'Vue'),
    ArcaneBadge(label: 'Angular'),
    ArcaneBadge(label: 'Svelte'),
  ],
)

Properties#

PropertyTypeDefaultDescription
children List<Component> [] Flow children
gap Gap? sm Space between items
rowGap Gap? null Vertical gap between rows
alignment JustifyContent? null Horizontal alignment
styles ArcaneStyleData? null Additional styling

With Gap#

ArcaneFlow(
  gap: Gap.md,
  children: [
    for (var tag in tags)
      ArcaneBadge(label: tag),
  ],
)

With Row Gap#

ArcaneFlow(
  gap: Gap.sm,
  rowGap: Gap.md,
  children: [
    for (var skill in skills)
      ArcaneChip(label: skill),
  ],
)

Alignment#

// Center aligned
ArcaneFlow(
  alignment: JustifyContent.center,
  gap: Gap.sm,
  children: [
    ArcaneButton(label: 'Option 1', onPressed: () {}),
    ArcaneButton(label: 'Option 2', onPressed: () {}),
    ArcaneButton(label: 'Option 3', onPressed: () {}),
  ],
)

// Space between
ArcaneFlow(
  alignment: JustifyContent.spaceBetween,
  children: [...],
)

Examples#

Tag Cloud#

ArcaneFlow(
  gap: Gap.sm,
  children: [
    ArcaneBadge(label: 'JavaScript'),
    ArcaneBadge(label: 'TypeScript'),
    ArcaneBadge(label: 'Python'),
    ArcaneBadge(label: 'Rust'),
    ArcaneBadge(label: 'Go'),
    ArcaneBadge(label: 'Dart'),
    ArcaneBadge(label: 'Swift'),
    ArcaneBadge(label: 'Kotlin'),
  ],
)

Filter Chips#

ArcaneFlow(
  gap: Gap.sm,
  children: [
    ArcaneChip(
      label: 'All',
      isSelected: filter == 'all',
      onPressed: () => setFilter('all'),
    ),
    ArcaneChip(
      label: 'Active',
      isSelected: filter == 'active',
      onPressed: () => setFilter('active'),
    ),
    ArcaneChip(
      label: 'Completed',
      isSelected: filter == 'completed',
      onPressed: () => setFilter('completed'),
    ),
    ArcaneChip(
      label: 'Archived',
      isSelected: filter == 'archived',
      onPressed: () => setFilter('archived'),
    ),
  ],
)
ArcaneFlow(
  alignment: JustifyContent.center,
  gap: Gap.md,
  children: [
    ArcaneIconButton(icon: span([text('𝕏')]), onPressed: () {}),
    ArcaneIconButton(icon: span([text('📘')]), onPressed: () {}),
    ArcaneIconButton(icon: span([text('📸')]), onPressed: () {}),
    ArcaneIconButton(icon: span([text('💼')]), onPressed: () {}),
    ArcaneIconButton(icon: span([text('🐙')]), onPressed: () {}),
  ],
)

Selected Tags#

ArcaneColumn(
  gap: Gap.sm,
  crossAxisAlignment: AlignItems.start,
  children: [
    ArcaneText('Selected tags:'),
    ArcaneFlow(
      gap: Gap.xs,
      children: [
        for (var tag in selectedTags)
          ArcaneChip(
            label: tag,
            trailing: span([text('×')]),
            onPressed: () => removeTag(tag),
          ),
        if (selectedTags.isEmpty)
          ArcaneText('No tags selected'),
      ],
    ),
  ],
)

Responsive Button Group#

ArcaneFlow(
  gap: Gap.sm,
  alignment: JustifyContent.center,
  children: [
    ArcaneButton(label: 'Save', onPressed: () {}),
    ArcaneButton.ghost(label: 'Preview', onPressed: () {}),
    ArcaneButton.ghost(label: 'Schedule', onPressed: () {}),
    ArcaneButton.destructive(label: 'Delete', onPressed: () {}),
  ],
)

Avatar List#

ArcaneFlow(
  gap: Gap.sm,
  children: [
    for (var user in teamMembers)
      ArcaneTooltip(
        content: user.name,
        child: ArcaneAvatar(
          imageUrl: user.avatar,
          size: AvatarSize.small,
        ),
      ),
    ArcaneIconButton(
      icon: span([text('+')]),
      size: IconButtonSize.small,
      onPressed: addMember,
    ),
  ],
)

Category Pills#

ArcaneFlow(
  gap: Gap.sm,
  rowGap: Gap.sm,
  styles: const ArcaneStyleData(
    padding: PaddingPreset.md,
    background: Background.surface,
    borderRadius: Radius.lg,
  ),
  children: [
    for (var category in categories)
      ArcaneButton(
        label: category.name,
        variant: selectedCategory == category.id
            ? ButtonVariant.primary
            : ButtonVariant.ghost,
        size: ButtonSize.small,
        onPressed: () => selectCategory(category.id),
      ),
  ],
)