@finsweet/webflow-apps-utils
v1.0.33
Published
Shared utilities for Webflow apps
Readme
Webflow Apps Utils
Internal Finsweet Library
Shared UI components and utilities for Finsweet's Webflow applications.
🔗 Live Storybook Documentation
Installation
pnpm add @finsweet/webflow-apps-utilsUsage
import '@finsweet/webflow-apps-utils/index.css';
import { Button, Modal, Input, siteInfo } from '@finsweet/webflow-apps-utils';Project Structure
src/
├── lib/
│ ├── router/ # Client-side routing utilities
│ ├── stores/ # Stores for state management
│ ├── types/ # TypeScript type definitions
│ ├── ui/ # UI components and styling
│ │ ├── components/ # Reusable UI components
│ │ └── icons/ # SVG icon components
│ └── utils/ # Helper functions and utilitiesCoding Standards
Naming Conventions
File and Folder Names
Folders: Use
kebab-casefor all directory names✅ custom-code/ ✅ webflow-canvas/ ✅ browser-storage/ ❌ customCode/ ❌ WebflowCanvas/Files: Use
camelCaseandPascalCasefor all file names✅ localStorage.ts ✅ handlePaste.ts ✅ getAllAssets.ts ✅ Button.svelte ✅ Form.svelte ❌ local-storage.ts ❌ handle_paste.ts ❌ form.svelte
Code Naming
- Components: Use
PascalCasefor component names - Functions: Use
camelCasefor function names - Variables: Use
camelCasefor variable names - Constants: Use
UPPERCASEfor constants - Types/Interfaces: Use
PascalCasefor type definitions
Documentation Standards
- Keep function documentation concise
Testing UI Components
Testing Strategy
All UI components should include comprehensive tests covering:
- Basic Rendering: Default props, custom props, and various configurations
- Component Variants: All available variants (primary, secondary, danger, etc.)
- Interactive States: Disabled, loading, invalid, and other state combinations
- User Interactions: Click events, keyboard navigation, and form submissions
- Accessibility: ARIA attributes, focus management, and screen reader support
- Visual Features: Icons, tooltips, custom styling, and layout variations
Test Structure
Use Vitest and Testing Library for component testing:
import { fireEvent, render, screen, waitFor } from '@testing-library/svelte';
import { describe, expect, it, vi } from 'vitest';
import Component from './Component.svelte';
describe('Component Name', () => {
describe('Basic Rendering', () => {
it('renders with default props', () => {
render(Component);
const element = screen.getByRole('...');
expect(element).toBeInTheDocument();
});
});
describe('Variants', () => {
// Test all component variants
});
describe('States', () => {
// Test disabled, loading, invalid states
});
describe('Events', () => {
// Test user interactions
});
describe('Accessibility', () => {
// Test ARIA attributes and keyboard navigation
});
});Testing Best Practices
- Comprehensive Coverage: Test all props, variants, and states
- User-Centric Tests: Focus on user interactions rather than implementation details
- Accessibility Testing: Verify ARIA attributes, keyboard navigation, and screen reader support
- Async Behavior: Use
waitForfor testing tooltips, modals, and dynamic content - Event Mocking: Mock external dependencies and event handlers properly
- State Verification: Check both visual state and underlying attributes
Example: Button Component Testing
// Testing component variants
const variants: ButtonVariant[] = ['primary', 'secondary', 'danger', 'cms'];
variants.forEach((variant) => {
it(`renders ${variant} variant correctly`, () => {
render(Button, { variant });
const button = screen.getByRole('button');
expect(button).toHaveClass(`button--${variant}`);
});
});
// Testing interactive states
it('renders loading state', () => {
render(Button, { loading: true });
const button = screen.getByRole('button');
expect(button).toBeDisabled();
expect(button).toHaveAttribute('aria-busy', 'true');
expect(button).toHaveClass('button--loading');
});
// Testing accessibility
it('has proper ARIA attributes', () => {
render(Button, { ariaLabel: 'Custom label', loading: true });
const button = screen.getByRole('button');
expect(button).toHaveAttribute('aria-label', 'Custom label');
expect(button).toHaveAttribute('aria-busy', 'true');
});
// Testing async interactions (tooltips)
it('shows tooltip on hover', async () => {
render(Button, {
tooltip: { message: 'Help text', listener: 'hover', listenerout: 'hover' }
});
const button = screen.getByRole('button');
const tooltipTarget = button.closest('.target');
await fireEvent.mouseEnter(tooltipTarget || button);
expect(screen.getByText('Help text')).toBeInTheDocument();
});Development
# Setup
pnpm install
# Development
pnpm dev # Start dev server
pnpm storybook # Component development
# Building & Testing
pnpm build # Build library
pnpm test # Run tests
pnpm lint # Check code quality
pnpm check # Check code qualityPublishing
Uses Changesets for automated releases. Create a changeset:
pnpm changesetPush changes to trigger automatic publishing to npm via GitHub Actions.
