Files
sigpro-ui/docs/components_old/fab.md
2026-04-02 19:31:39 +02:00

27 KiB
Raw Blame History

Fab

Floating Action Button (FAB) component for primary actions with expandable menu options. Each example uses a container with position: relative and explicit height to position the FAB correctly.

Tag

Fab

Props

Prop Type Default Description
icon string | VNode | Signal - Main FAB icon
label string | VNode | Signal - Text label for main button
actions Array<Action> | Signal<Array> [] Array of action buttons that expand from FAB
position string 'bottom-6 right-6' CSS position classes (e.g., 'bottom-6 left-6')
class string '' Additional CSS classes (DaisyUI + Tailwind)

Action Structure

Property Type Description
label string | VNode Label text shown next to action button
icon string | VNode Icon for the action button
onclick function Click handler
class string Additional CSS classes for the action button

Live Examples

Basic FAB

Live Demo

const BasicDemo = () => {
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Fab({
      icon: '',
      actions: [
        { icon: '📝', label: 'New Note', onclick: () => Toast('Create note', 'alert-info', 2000) },
        { icon: '📷', label: 'Take Photo', onclick: () => Toast('Open camera', 'alert-info', 2000) },
        { icon: '📎', label: 'Attach File', onclick: () => Toast('Attach file', 'alert-info', 2000) }
      ]
    })
  ]);
};
$mount(BasicDemo, '#demo-basic');

With Label

Live Demo

const LabelDemo = () => {
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Fab({
      label: 'Create',
      icon: '✨',
      actions: [
        { icon: '📝', label: 'Document', onclick: () => Toast('New document', 'alert-success', 2000) },
        { icon: '🎨', label: 'Design', onclick: () => Toast('New design', 'alert-success', 2000) },
        { icon: '📊', label: 'Spreadsheet', onclick: () => Toast('New spreadsheet', 'alert-success', 2000) }
      ]
    })
  ]);
};
$mount(LabelDemo, '#demo-label');

Different Positions

Live Demo

const PositionsDemo = () => {
  const position = $('bottom-6 right-6');
  
  return Div({ class: 'relative h-[500px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute top-4 left-4 z-20 bg-base-200 p-2 rounded-lg shadow' }, [
      Select({
        value: position,
        options: [
          { value: 'bottom-6 right-6', label: 'Bottom Right' },
          { value: 'bottom-6 left-6', label: 'Bottom Left' },
          { value: 'top-6 right-6', label: 'Top Right' },
          { value: 'top-6 left-6', label: 'Top Left' }
        ],
        onchange: (e) => position(e.target.value)
      })
    ]),
    Div({ class: 'absolute inset-0 flex items-center justify-center text-sm opacity-50 pointer-events-none' }, [
      'FAB position changes relative to this container'
    ]),
    Fab({
      position: () => position(),
      icon: '🧭',
      actions: [
        { icon: '⬅️', label: 'Bottom Left', onclick: () => position('bottom-6 left-6') },
        { icon: '➡️', label: 'Bottom Right', onclick: () => position('bottom-6 right-6') },
        { icon: '⬆️', label: 'Top Right', onclick: () => position('top-6 right-6') },
        { icon: '⬇️', label: 'Top Left', onclick: () => position('top-6 left-6') }
      ]
    })
  ]);
};
$mount(PositionsDemo, '#demo-positions');

Color Variants

Live Demo

const ColorsDemo = () => {
  const variant = $('primary');
  
  const variants = {
    primary: { class: 'btn-primary', icon: '🔵' },
    secondary: { class: 'btn-secondary', icon: '🟣' },
    accent: { class: 'btn-accent', icon: '🔴' },
    info: { class: 'btn-info', icon: '🔷' },
    success: { class: 'btn-success', icon: '🟢' },
    warning: { class: 'btn-warning', icon: '🟡' },
    error: { class: 'btn-error', icon: '🔴' }
  };
  
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute top-4 left-4 z-20 bg-base-200 p-2 rounded-lg shadow' }, [
      Select({
        value: variant,
        options: Object.keys(variants).map(v => ({ value: v, label: v.charAt(0).toUpperCase() + v.slice(1) })),
        onchange: (e) => variant(e.target.value)
      })
    ]),
    Fab({
      class: variants[variant()].class,
      icon: variants[variant()].icon,
      actions: [
        { icon: '📝', label: 'Action 1', onclick: () => Toast('Action 1', 'alert-info', 2000) },
        { icon: '🎨', label: 'Action 2', onclick: () => Toast('Action 2', 'alert-info', 2000) },
        { icon: '⚙️', label: 'Action 3', onclick: () => Toast('Action 3', 'alert-info', 2000) }
      ]
    })
  ]);
};
$mount(ColorsDemo, '#demo-colors');

Reactive Actions

Live Demo

const ReactiveActions = () => {
  const count = $(0);
  
  const actions = () => [
    { 
      icon: '🔢', 
      label: `Count: ${count()}`, 
      onclick: () => {} 
    },
    { 
      icon: '', 
      label: 'Increment', 
      onclick: () => count(count() + 1) 
    },
    { 
      icon: '', 
      label: 'Decrement', 
      onclick: () => count(count() - 1) 
    },
    { 
      icon: '🔄', 
      label: 'Reset', 
      onclick: () => count(0) 
    }
  ];
  
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Fab({
      icon: () => count() > 0 ? `🔢 ${count()}` : '🎛️',
      actions: actions
    })
  ]);
};
$mount(ReactiveActions, '#demo-reactive');

Document Actions

Live Demo

const DocumentActions = () => {
  const saved = $(false);
  
  const handleSave = () => {
    saved(true);
    Toast('Document saved!', 'alert-success', 2000);
    setTimeout(() => saved(false), 3000);
  };
  
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute inset-0 flex flex-col items-center justify-center' }, [
      Div({ class: 'text-6xl mb-4' }, '📄'),
      Div({ class: 'text-sm opacity-70' }, 'Untitled Document'),
      () => saved() ? Div({ class: 'mt-4' }, Alert({ type: 'success', message: '✓ Saved successfully' })) : null
    ]),
    Fab({
      icon: '✏️',
      actions: [
        { icon: '💾', label: 'Save', onclick: handleSave },
        { icon: '📋', label: 'Copy', onclick: () => Toast('Copied!', 'alert-info', 2000) },
        { icon: '✂️', label: 'Cut', onclick: () => Toast('Cut!', 'alert-info', 2000) },
        { icon: '📎', label: 'Share', onclick: () => Toast('Share dialog', 'alert-info', 2000) }
      ]
    })
  ]);
};
$mount(DocumentActions, '#demo-document');

Messaging FAB

Live Demo

const MessagingFAB = () => {
  const unread = $(3);
  
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute inset-0 flex flex-col items-center justify-center' }, [
      Div({ class: 'text-6xl mb-4' }, '💬'),
      Div({ class: 'text-sm opacity-70' }, 'Messages'),
      () => unread() > 0 ? Div({ class: 'badge badge-error mt-2' }, `${unread()} unread`) : null
    ]),
    Fab({
      icon: () => `💬${unread() > 0 ? ` ${unread()}` : ''}`,
      class: 'btn-primary',
      actions: [
        { 
          icon: '👤', 
          label: 'New Message', 
          onclick: () => Toast('Start new conversation', 'alert-info', 2000) 
        },
        { 
          icon: '👥', 
          label: 'Group Chat', 
          onclick: () => Toast('Create group', 'alert-info', 2000) 
        },
        { 
          icon: '📞', 
          label: 'Voice Call', 
          onclick: () => Toast('Start call', 'alert-info', 2000) 
        },
        { 
          icon: '📹', 
          label: 'Video Call', 
          onclick: () => Toast('Start video call', 'alert-info', 2000) 
        },
        { 
          icon: '🔔', 
          label: () => `Mark as read (${unread()})`, 
          onclick: () => {
            unread(0);
            Toast('All messages read', 'alert-success', 2000);
          } 
        }
      ]
    })
  ]);
};
$mount(MessagingFAB, '#demo-messaging');

Flower Style FAB

Live Demo

const FlowerDemo = () => {
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute inset-0 flex items-center justify-center text-sm opacity-50' }, [
      'Flower style FAB (quarter circle arrangement)'
    ]),
    Fab({
      icon: '🌸',
      class: 'fab-flower',
      actions: [
        { icon: '📷', label: 'Camera', onclick: () => Toast('Camera', 'alert-info', 2000) },
        { icon: '🎨', label: 'Gallery', onclick: () => Toast('Gallery', 'alert-info', 2000) },
        { icon: '🎤', label: 'Voice', onclick: () => Toast('Voice', 'alert-info', 2000) },
        { icon: '📍', label: 'Location', onclick: () => Toast('Location', 'alert-info', 2000) }
      ]
    })
  ]);
};
$mount(FlowerDemo, '#demo-flower');

All Variants

Live Demo

const VariantsDemo = () => {
  const actions = [
    { icon: '⭐', label: 'Favorite', onclick: () => Toast('Favorited', 'alert-info', 2000) },
    { icon: '🔔', label: 'Remind', onclick: () => Toast('Reminder set', 'alert-info', 2000) },
    { icon: '📅', label: 'Schedule', onclick: () => Toast('Scheduled', 'alert-info', 2000) }
  ];
  
  return Div({ class: 'relative h-[400px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'grid grid-cols-2 gap-4 p-4 h-full' }, [
      Div({ class: 'relative border rounded-lg bg-base-200' }, [
        Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Primary'),
        Fab({ icon: '🔵', class: 'btn-primary', actions, position: 'bottom-6 left-6' })
      ]),
      Div({ class: 'relative border rounded-lg bg-base-200' }, [
        Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Secondary'),
        Fab({ icon: '🟣', class: 'btn-secondary', actions, position: 'bottom-6 right-6' })
      ]),
      Div({ class: 'relative border rounded-lg bg-base-200' }, [
        Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Accent'),
        Fab({ icon: '🔴', class: 'btn-accent', actions, position: 'top-6 left-6' })
      ]),
      Div({ class: 'relative border rounded-lg bg-base-200' }, [
        Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Success'),
        Fab({ icon: '🟢', class: 'btn-success', actions, position: 'top-6 right-6' })
      ])
    ])
  ]);
};
$mount(VariantsDemo, '#demo-variants');
<script> (function() { const initFabExamples = () => { // 1. Basic FAB const basicTarget = document.querySelector('#demo-basic'); if (basicTarget && !basicTarget.hasChildNodes()) { const BasicDemo = () => { return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Fab({ icon: '', actions: [ { icon: '📝', label: 'New Note', onclick: () => Toast('Create note', 'alert-info', 2000) }, { icon: '📷', label: 'Take Photo', onclick: () => Toast('Open camera', 'alert-info', 2000) }, { icon: '📎', label: 'Attach File', onclick: () => Toast('Attach file', 'alert-info', 2000) } ] }) ]); }; $mount(BasicDemo, basicTarget); } // 2. With Label const labelTarget = document.querySelector('#demo-label'); if (labelTarget && !labelTarget.hasChildNodes()) { const LabelDemo = () => { return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Fab({ label: 'Create', icon: '', actions: [ { icon: '📝', label: 'Document', onclick: () => Toast('New document', 'alert-success', 2000) }, { icon: '🎨', label: 'Design', onclick: () => Toast('New design', 'alert-success', 2000) }, { icon: '📊', label: 'Spreadsheet', onclick: () => Toast('New spreadsheet', 'alert-success', 2000) } ] }) ]); }; $mount(LabelDemo, labelTarget); } // 3. Different Positions const positionsTarget = document.querySelector('#demo-positions'); if (positionsTarget && !positionsTarget.hasChildNodes()) { const PositionsDemo = () => { const position = $('bottom-6 right-6'); return Div({ class: 'relative h-[500px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Div({ class: 'absolute top-4 left-4 z-20 bg-base-200 p-2 rounded-lg shadow' }, [ Select({ value: position, options: [ { value: 'bottom-6 right-6', label: 'Bottom Right' }, { value: 'bottom-6 left-6', label: 'Bottom Left' }, { value: 'top-6 right-6', label: 'Top Right' }, { value: 'top-6 left-6', label: 'Top Left' } ], onchange: (e) => position(e.target.value) }) ]), Div({ class: 'absolute inset-0 flex items-center justify-center text-sm opacity-50 pointer-events-none' }, [ 'FAB position changes relative to this container' ]), Fab({ position: () => position(), icon: '🧭', actions: [ { icon: '⬅️', label: 'Bottom Left', onclick: () => position('bottom-6 left-6') }, { icon: '➡️', label: 'Bottom Right', onclick: () => position('bottom-6 right-6') }, { icon: '⬆️', label: 'Top Right', onclick: () => position('top-6 right-6') }, { icon: '⬇️', label: 'Top Left', onclick: () => position('top-6 left-6') } ] }) ]); }; $mount(PositionsDemo, positionsTarget); } // 4. Color Variants const colorsTarget = document.querySelector('#demo-colors'); if (colorsTarget && !colorsTarget.hasChildNodes()) { const ColorsDemo = () => { const variant = $('primary'); const variants = { primary: { class: 'btn-primary', icon: '🔵' }, secondary: { class: 'btn-secondary', icon: '🟣' }, accent: { class: 'btn-accent', icon: '🔴' }, info: { class: 'btn-info', icon: '🔷' }, success: { class: 'btn-success', icon: '🟢' }, warning: { class: 'btn-warning', icon: '🟡' }, error: { class: 'btn-error', icon: '🔴' } }; return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Div({ class: 'absolute top-4 left-4 z-20 bg-base-200 p-2 rounded-lg shadow' }, [ Select({ value: variant, options: Object.keys(variants).map(v => ({ value: v, label: v.charAt(0).toUpperCase() + v.slice(1) })), onchange: (e) => variant(e.target.value) }) ]), Fab({ class: variants[variant()].class, icon: variants[variant()].icon, actions: [ { icon: '📝', label: 'Action 1', onclick: () => Toast('Action 1', 'alert-info', 2000) }, { icon: '🎨', label: 'Action 2', onclick: () => Toast('Action 2', 'alert-info', 2000) }, { icon: '⚙️', label: 'Action 3', onclick: () => Toast('Action 3', 'alert-info', 2000) } ] }) ]); }; $mount(ColorsDemo, colorsTarget); } // 5. Reactive Actions const reactiveTarget = document.querySelector('#demo-reactive'); if (reactiveTarget && !reactiveTarget.hasChildNodes()) { const ReactiveActions = () => { const count = $(0); const actions = () => [ { icon: '🔢', label: `Count: ${count()}`, onclick: () => {} }, { icon: '', label: 'Increment', onclick: () => count(count() + 1) }, { icon: '', label: 'Decrement', onclick: () => count(count() - 1) }, { icon: '🔄', label: 'Reset', onclick: () => count(0) } ]; return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Fab({ icon: () => count() > 0 ? `🔢 ${count()}` : '🎛️', actions: actions }) ]); }; $mount(ReactiveActions, reactiveTarget); } // 6. Document Actions const documentTarget = document.querySelector('#demo-document'); if (documentTarget && !documentTarget.hasChildNodes()) { const DocumentActions = () => { const saved = $(false); const handleSave = () => { saved(true); Toast('Document saved!', 'alert-success', 2000); setTimeout(() => saved(false), 3000); }; return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Div({ class: 'absolute inset-0 flex flex-col items-center justify-center' }, [ Div({ class: 'text-6xl mb-4' }, '📄'), Div({ class: 'text-sm opacity-70' }, 'Untitled Document'), () => saved() ? Div({ class: 'mt-4' }, Alert({ type: 'success', message: '✓ Saved successfully' })) : null ]), Fab({ icon: '✏️', actions: [ { icon: '💾', label: 'Save', onclick: handleSave }, { icon: '📋', label: 'Copy', onclick: () => Toast('Copied!', 'alert-info', 2000) }, { icon: '✂️', label: 'Cut', onclick: () => Toast('Cut!', 'alert-info', 2000) }, { icon: '📎', label: 'Share', onclick: () => Toast('Share dialog', 'alert-info', 2000) } ] }) ]); }; $mount(DocumentActions, documentTarget); } // 7. Messaging FAB const messagingTarget = document.querySelector('#demo-messaging'); if (messagingTarget && !messagingTarget.hasChildNodes()) { const MessagingFAB = () => { const unread = $(3); return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Div({ class: 'absolute inset-0 flex flex-col items-center justify-center' }, [ Div({ class: 'text-6xl mb-4' }, '💬'), Div({ class: 'text-sm opacity-70' }, 'Messages'), () => unread() > 0 ? Div({ class: 'badge badge-error mt-2' }, `${unread()} unread`) : null ]), Fab({ icon: () => `💬${unread() > 0 ? ` ${unread()}` : ''}`, class: 'btn-primary', actions: [ { icon: '👤', label: 'New Message', onclick: () => Toast('Start new conversation', 'alert-info', 2000) }, { icon: '👥', label: 'Group Chat', onclick: () => Toast('Create group', 'alert-info', 2000) }, { icon: '📞', label: 'Voice Call', onclick: () => Toast('Start call', 'alert-info', 2000) }, { icon: '📹', label: 'Video Call', onclick: () => Toast('Start video call', 'alert-info', 2000) }, { icon: '🔔', label: () => `Mark as read (${unread()})`, onclick: () => { unread(0); Toast('All messages read', 'alert-success', 2000); } } ] }) ]); }; $mount(MessagingFAB, messagingTarget); } // 8. Flower Style FAB const flowerTarget = document.querySelector('#demo-flower'); if (flowerTarget && !flowerTarget.hasChildNodes()) { const FlowerDemo = () => { return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Div({ class: 'absolute inset-0 flex items-center justify-center text-sm opacity-50' }, [ 'Flower style FAB (quarter circle arrangement)' ]), Fab({ icon: '🌸', class: 'fab-flower', actions: [ { icon: '📷', label: 'Camera', onclick: () => Toast('Camera', 'alert-info', 2000) }, { icon: '🎨', label: 'Gallery', onclick: () => Toast('Gallery', 'alert-info', 2000) }, { icon: '🎤', label: 'Voice', onclick: () => Toast('Voice', 'alert-info', 2000) }, { icon: '📍', label: 'Location', onclick: () => Toast('Location', 'alert-info', 2000) } ] }) ]); }; $mount(FlowerDemo, flowerTarget); } // 9. All Variants const variantsTarget = document.querySelector('#demo-variants'); if (variantsTarget && !variantsTarget.hasChildNodes()) { const VariantsDemo = () => { const actions = [ { icon: '', label: 'Favorite', onclick: () => Toast('Favorited', 'alert-info', 2000) }, { icon: '🔔', label: 'Remind', onclick: () => Toast('Reminder set', 'alert-info', 2000) }, { icon: '📅', label: 'Schedule', onclick: () => Toast('Scheduled', 'alert-info', 2000) } ]; return Div({ class: 'relative h-[400px] w-full bg-base-100 rounded-lg overflow-hidden' }, [ Div({ class: 'grid grid-cols-2 gap-4 p-4 h-full' }, [ Div({ class: 'relative border rounded-lg bg-base-200' }, [ Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Primary'), Fab({ icon: '🔵', class: 'btn-primary', actions, position: 'bottom-6 left-6' }) ]), Div({ class: 'relative border rounded-lg bg-base-200' }, [ Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Secondary'), Fab({ icon: '🟣', class: 'btn-secondary', actions, position: 'bottom-6 right-6' }) ]), Div({ class: 'relative border rounded-lg bg-base-200' }, [ Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Accent'), Fab({ icon: '🔴', class: 'btn-accent', actions, position: 'top-6 left-6' }) ]), Div({ class: 'relative border rounded-lg bg-base-200' }, [ Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Success'), Fab({ icon: '🟢', class: 'btn-success', actions, position: 'top-6 right-6' }) ]) ]) ]); }; $mount(VariantsDemo, variantsTarget); } }; initFabExamples(); if (window.$docsify) { window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => { hook.doneEach(initFabExamples); }); } })(); </script>