npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@snapdragonsnursery/react-components

v1.19.7

Published

A collection of reusable React components for Snapdragons Nursery applications.

Readme

@snapdragonsnursery/react-components

A collection of reusable React components for Snapdragons Nursery applications.

Components

  • ChildSearchModal: Advanced child search and selection component with filtering, pagination, and multi-select capabilities
  • ChildSearchFilters: Advanced filtering component with date range picker, status, site, and age filters (includes Apply button for better UX)
  • EmployeeSelect: Lightweight, searchable employee selector with grouping and optional avatars
  • EmployeeSearchModal: Advanced employee search with server-side filtering, pagination, and complex filters
  • DateRangePicker: Shadcn-style date range picker component (supports optional presets)
  • DatePicker: Shadcn-style single date picker component
  • Calendar: Official shadcn calendar component
  • Popover: Official shadcn popover component
  • AuthButtons: Authentication buttons for MSAL integration
  • ThemeToggle: Dark/light theme toggle component
  • LandingPage: Landing page component with authentication
  • SoftWarningAlert: Soft-styled alert for non-blocking warnings with optional action

Installation

npm install @snapdragonsnursery/react-components

Quick Start

import { ChildSearchModal } from '@snapdragonsnursery/react-components';

function MyComponent() {
  const [isModalOpen, setIsModalOpen] = useState(false);
  
  return (
    <ChildSearchModal
      isOpen={isModalOpen}
      onClose={() => setIsModalOpen(false)}
      onSelect={(child) => console.log('Selected:', child)}
      title="Search for a Child"
    />
  );
}

EmployeeSelect Example

import { EmployeeSelect } from '@snapdragonsnursery/react-components';

function MyComponent() {
  const [selectedEntraId, setSelectedEntraId] = useState();
  const employees = [
    {
      entra_id: '123-456',
      full_name: 'Jane Smith',
      site_name: 'Main Office',
      role_name: 'Teacher',
      employee_id: 'EMP001',
      email: '[email protected]',
      employee_status: 'Active'
    },
    // ... more employees
  ];

  return (
    <EmployeeSelect
      value={selectedEntraId}
      onChange={setSelectedEntraId}
      items={employees}
      groupBy="site"
      showAvatar
      showSiteName
      placeholder="Select an employee..."
    />
  );
}

EmployeeSelect vs EmployeeSearchModal:

  • EmployeeSelect: Use for simple dropdown selection with pre-loaded employee data. Supports grouping by site/role, optional avatars, and built-in client-side search. Perfect for forms with limited employee lists.
  • EmployeeSearchModal: Use for advanced search scenarios requiring server-side filtering, pagination, complex multi-criteria filters, and multi-select. Ideal for large employee databases.

SoftWarningAlert Example

import { SoftWarningAlert } from '@snapdragonsnursery/react-components';
import { AlertTriangle } from 'lucide-react';

function Notice() {
  return (
    <SoftWarningAlert
      icon={AlertTriangle}
      title="Unsubmitted claims"
      description="You have 3 unsubmitted mileage claims. Create a report to submit."
      actionLabel="Create report"
      onAction={() => console.log('clicked')}
    />
  );
}

Shadcn Components

This package includes official shadcn components with proper styling. The components use shadcn CSS variables, so make sure your consuming project has the shadcn CSS variables defined in your CSS file.

For Consuming Projects

  1. Ensure your project has shadcn CSS variables in your main CSS file (like src/index.css):
@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --primary: 221.2 83.2% 53.3%;
    --primary-foreground: 210 40% 98%;
    --accent: 210 40% 96%;
    --accent-foreground: 222.2 84% 4.9%;
    --muted: 210 40% 96%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 221.2 83.2% 53.3%;
    --radius: 0.5rem;
  }
}
  1. Update your Tailwind config to include the react-components package:
// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{js,ts,jsx,tsx}',
    './node_modules/@snapdragonsnursery/react-components/src/**/*.{js,jsx}'
  ],
  // ... rest of your config
}
  1. Install tailwindcss-animate for proper animations:
npm install tailwindcss-animate

Date Range Picker Example

import { DateRangePicker } from '@snapdragonsnursery/react-components';

function MyComponent() {
  const [selectedRange, setSelectedRange] = useState(null);

  const handleDateRangeChange = (range) => {
    // Only update your filters when both dates are selected
    if (range?.from && range?.to) {
      // Both dates selected - update your filters
      setFilters(prev => ({
        ...prev,
        dobFrom: range.from.toISOString().split('T')[0],
        dobTo: range.to.toISOString().split('T')[0],
      }));
    } else if (!range?.from && !range?.to) {
      // Range cleared - clear your filters
      setFilters(prev => ({
        ...prev,
        dobFrom: '',
        dobTo: '',
      }));
    }
    // Don't update filters when only first date is selected
    
    setSelectedRange(range);
  };

  return (
    <>
      <DateRangePicker
        selectedRange={selectedRange}
        onSelect={handleDateRangeChange}
        placeholder="Select a date range"
        numberOfMonths={2}
      />
      {/* With presets */}
      <DateRangePicker
        selectedRange={selectedRange}
        onSelect={handleDateRangeChange}
        presetsEnabled
        presets={[
          { key: 'thisWeek', label: 'This week', getRange: () => ({ from: startOfWeek(new Date(), { weekStartsOn: 1 }), to: new Date() }) },
          { key: 'lastWeek', label: 'Last week', getRange: () => { const ref = subWeeks(new Date(), 1); return { from: startOfWeek(ref, { weekStartsOn: 1 }), to: endOfWeek(ref, { weekStartsOn: 1 }) } } },
          { key: 'thisMonth', label: 'This month', getRange: () => ({ from: startOfMonth(new Date()), to: new Date() }) },
          { key: 'lastMonth', label: 'Last month', getRange: () => { const ref = subMonths(new Date(), 1); return { from: startOfMonth(ref), to: endOfMonth(ref) } } },
          { key: 'thisYear', label: 'This year', getRange: () => ({ from: startOfYear(new Date()), to: new Date() }) },
          { key: 'lastYear', label: 'Last year', getRange: () => { const ref = subYears(new Date(), 1); return { from: startOfYear(ref), to: endOfYear(ref) } } },
        ]}
      />
    </>
  );
}

Important: The DateRangePicker now maintains its own internal state and only calls onSelect when both dates are selected or when the range is cleared. This prevents premature re-renders and keeps the calendar open until the user completes their selection. The ChildSearchFilters component includes an "Apply Filters" button that only triggers searches when clicked, providing better user control.

Apply Button Functionality

The ChildSearchFilters component now includes an "Apply Filters" button that provides better user control:

  • Local State: Filter changes are stored locally until applied
  • Visual Feedback: Shows "You have unsaved filter changes" when filters are modified
  • Apply Button: Only triggers search when clicked
  • Cancel Button: Reverts changes without applying
  • Better UX: Users can configure multiple filters before searching
<ChildSearchFilters
  filters={filters}
  onFiltersChange={setFilters}
  onApplyFilters={setFilters} // New callback for applying filters
  sites={sites}
  // ... other props
/>

Environment Variables

Set this environment variable in your application:

VITE_APIM_SCOPE=api://your-apim-app-id/.default

Documentation


🚀 Publishing New Versions

Quick Release (Recommended)

# Patch release (bug fixes) - 1.1.0 → 1.1.1
npm run release

# Minor release (new features) - 1.1.0 → 1.2.0
npm run release:minor

# Major release (breaking changes) - 1.1.0 → 2.0.0
npm run release:major

GitHub Actions (Web Interface)

  1. Go to GitHub Actions
  2. Click "Publish Package"
  3. Click "Run workflow"
  4. Select version type (patch/minor/major)
  5. Click "Run workflow"

Manual Commands

# Just bump version
npm run version:patch
npm run version:minor
npm run version:major

# Bump and publish
npm run publish:patch
npm run publish:minor
npm run publish:major

Pre-release Versions (Beta)

# Create beta version
npm run publish:prepatch
npm run publish:preminor
npm run publish:premajor

# Install beta in consuming apps
npm install @snapdragonsnursery/react-components@beta

Version Types

| Type | Example | Use Case | |------|---------|----------| | patch | 1.1.0 → 1.1.1 | Bug fixes, documentation | | minor | 1.1.0 → 1.2.0 | New features, backward compatible | | major | 1.1.0 → 2.0.0 | Breaking changes | | prepatch | 1.1.0 → 1.1.1-0 | Beta patch release | | preminor | 1.1.0 → 1.2.0-0 | Beta minor release | | premajor | 1.1.0 → 2.0.0-0 | Beta major release |

Release Checklist

Before releasing:

  • [ ] All changes committed and pushed
  • [ ] Tests pass (if configured)
  • [ ] Documentation updated
  • [ ] Version type selected (patch/minor/major)
  • [ ] NPM token configured (for GitHub Actions)

Troubleshooting

Common Issues

"Working directory not clean"

git add .
git commit -m "Prepare for release"

"Not on main branch"

git checkout main
git pull origin main

"NPM authentication failed"

  • Check GitHub Secrets → NPM_TOKEN
  • Verify token has publish permissions

"Version already exists"

npm run release:minor  # Use different version type

Support

For issues with components or release process:

  1. Check component documentation
  2. Review Release Guide
  3. Check GitHub Actions logs
  4. Contact the development team

Contributing

  1. Make changes in feature branch
  2. Test locally
  3. Create pull request
  4. Merge to main
  5. Release using one of the methods above

Current Version: 1.1.0
Last Updated: January 2024