UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

469 lines (360 loc) 13.9 kB
# @furystack/shades-common-components Common and reusable UI components for FuryStack Shades. ## Installation ```bash npm install @furystack/shades-common-components # or yarn add @furystack/shades-common-components ``` ## Components ### Button A styled button component with contained and outlined variants. ```tsx import { Button } from '@furystack/shades-common-components' // Contained button (default) <Button onclick={() => console.log('Clicked!')}>Click me</Button> // Outlined button <Button variant="outlined" color="primary">Outlined</Button> // Disabled button <Button disabled>Disabled</Button> // With color <Button variant="contained" color="error">Delete</Button> ``` ### Input A styled text input with validation support. ```tsx import { Input } from '@furystack/shades-common-components' // Basic input <Input labelTitle="Username" placeholder="Enter your username" onTextChange={(value) => console.log(value)} /> // With validation <Input labelTitle="Email" type="email" required variant="outlined" getValidationResult={({ state }) => { if (!state.value.includes('@')) { return { isValid: false, message: 'Please enter a valid email' } } return { isValid: true } }} /> // Contained variant <Input labelTitle="Password" type="password" variant="contained" defaultColor="primary" /> ``` ### Modal A modal dialog component. ```tsx import { Modal } from '@furystack/shades-common-components' import { ObservableValue } from '@furystack/utils' const isVisible = new ObservableValue(false) <Button onclick={() => isVisible.setValue(true)}>Open Modal</Button> <Modal isVisible={isVisible} onClose={() => isVisible.setValue(false)} backdropStyle={{ background: 'rgba(0, 0, 0, 0.5)' }} > <div onclick={(e) => e.stopPropagation()}> <h2>Modal Title</h2> <p>Modal content goes here</p> <Button onclick={() => isVisible.setValue(false)}>Close</Button> </div> </Modal> ``` ### DataGrid A data grid component for displaying tabular data. ```tsx import { DataGrid, CollectionService } from '@furystack/shades-common-components' type User = { id: number; name: string; email: string } const collectionService = new CollectionService<User>({ /* options */ }) const findOptions = { top: 10, skip: 0 } <DataGrid<User, 'name' | 'email'> columns={['name', 'email']} collectionService={collectionService} findOptions={findOptions} onFindOptionsChange={(newOptions) => { /* handle options change */ }} headerComponents={{ name: () => <span>Name</span>, email: () => <span>Email</span>, }} rowComponents={{ name: (user) => <span>{user.name}</span>, email: (user) => <span>{user.email}</span>, }} styles={{ container: { minHeight: '400px' } }} /> ``` ### AppBar A top navigation bar component. ```tsx import { AppBar, AppBarLink } from '@furystack/shades-common-components' ;<AppBar> <h1>My App</h1> <AppBarLink href="/">Home</AppBarLink> <AppBarLink href="/about">About</AppBarLink> </AppBar> ``` ### Tabs A tabbed interface component. ```tsx import { Tabs } from '@furystack/shades-common-components' ;<Tabs tabs={[ { header: <span>Tab 1</span>, component: <div>Content 1</div> }, { header: <span>Tab 2</span>, component: <div>Content 2</div> }, ]} /> ``` ### CacheView Renders the state of a cache entry. Takes a `Cache` instance and `args`, subscribes to the observable, and handles loading, error (with retry), and loaded/obsolete states. ```tsx import { CacheView } from '@furystack/shades-common-components' import type { CacheWithValue } from '@furystack/cache' const UserContent = Shade<{ data: CacheWithValue<User> }>({ customElementName: 'user-content', render: ({ props }) => <div>{props.data.value.name}</div>, }) // Basic usage <CacheView cache={userCache} args={[userId]} content={UserContent} /> // With custom loader and error <CacheView cache={userCache} args={[userId]} content={UserContent} loader={<Skeleton />} error={(err, retry) => <Alert severity="error"><Button onclick={retry}>Retry</Button></Alert>} /> ``` ### Loader A loading spinner component. ```tsx import { Loader } from '@furystack/shades-common-components' ;<Loader /> ``` ### Paper A container component with elevation. ```tsx import { Paper } from '@furystack/shades-common-components' ;<Paper> <p>Content with elevated background</p> </Paper> ``` ### Avatar An avatar component for displaying user images or initials. ```tsx import { Avatar } from '@furystack/shades-common-components' ;<Avatar userName="John Doe" /> ``` ### FAB (Floating Action Button) A floating action button component. ```tsx import { Fab } from '@furystack/shades-common-components' ;<Fab onclick={() => console.log('FAB clicked')}>+</Fab> ``` ### Typography A text component that renders semantic HTML elements (`h1`–`h6`, `p`, `span`) based on the `variant` prop. ```tsx import { Typography } from '@furystack/shades-common-components' // Heading <Typography variant="h1">Page Title</Typography> // Body text (default variant is 'body1') <Typography>Regular paragraph text</Typography> // With color <Typography variant="h3" color="primary">Primary Heading</Typography> <Typography color="textSecondary">Secondary text</Typography> // Truncated with ellipsis (single line) <Typography ellipsis>This text will be truncated if it overflows...</Typography> // Multi-line clamp <Typography ellipsis={3}>This text will be clamped to 3 lines...</Typography> // Copyable <Typography copyable>Click the icon to copy this text</Typography> // Alignment and gutter <Typography align="center" gutterBottom>Centered with bottom margin</Typography> ``` **Variants:** `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `subtitle1`, `subtitle2`, `body1`, `body2`, `caption`, `overline` **Colors:** Any palette key (`primary`, `secondary`, `error`, `warning`, `success`, `info`) or `textPrimary`, `textSecondary`, `textDisabled` ## Theming The component library includes a CSS-variable-based theming system with runtime theme switching. ### Available Themes Two default themes are included in the main entry point: | Theme | Export | Description | | ------------- | ------------------- | ----------------------------- | | Default Light | `defaultLightTheme` | Light theme with system fonts | | Default Dark | `defaultDarkTheme` | Dark theme with system fonts | 17 additional pop-culture-inspired themes are available as deep imports for tree-shaking: | Theme | Import Path | Inspiration | | ------------- | ---------------------------------------------------------- | ------------------------ | | Architect | `@furystack/shades-common-components/themes/architect` | The Matrix | | Auditore | `@furystack/shades-common-components/themes/auditore` | Assassin's Creed | | Black Mesa | `@furystack/shades-common-components/themes/black-mesa` | Half-Life | | Chieftain | `@furystack/shades-common-components/themes/chieftain` | Warcraft 1 Orc faction | | Dragonborn | `@furystack/shades-common-components/themes/dragonborn` | Skyrim | | Hawkins | `@furystack/shades-common-components/themes/hawkins` | Stranger Things | | Jedi | `@furystack/shades-common-components/themes/jedi` | Star Wars (Jedi Order) | | Neon Runner | `@furystack/shades-common-components/themes/neon-runner` | Cyberpunk | | Paladin | `@furystack/shades-common-components/themes/paladin` | Warcraft 1 Human faction | | Plumber | `@furystack/shades-common-components/themes/plumber` | Super Mario | | Replicant | `@furystack/shades-common-components/themes/replicant` | Blade Runner | | Sandworm | `@furystack/shades-common-components/themes/sandworm` | Dune | | Shadow Broker | `@furystack/shades-common-components/themes/shadow-broker` | Mass Effect | | Sith | `@furystack/shades-common-components/themes/sith` | Star Wars (Sith Order) | | Vault Dweller | `@furystack/shades-common-components/themes/vault-dweller` | Fallout | | Wild Hunt | `@furystack/shades-common-components/themes/wild-hunt` | The Witcher 3 | | Xenomorph | `@furystack/shades-common-components/themes/xenomorph` | Alien | ### Applying a Theme Use `useThemeCssVariables` to set CSS variables on `:root`: ```tsx import { useThemeCssVariables, defaultLightTheme } from '@furystack/shades-common-components' // Apply on startup useThemeCssVariables(defaultLightTheme) ``` For reactive theme switching through the injector, resolve the `ThemeProviderService` token: ```tsx import { ThemeProviderService, defaultDarkTheme } from '@furystack/shades-common-components' const themeProvider = injector.get(ThemeProviderService) themeProvider.setAssignedTheme(defaultDarkTheme) // Listen for changes themeProvider.subscribe('themeChanged', (theme) => { console.log('Theme changed:', theme.name) }) ``` Deep-imported themes can be loaded lazily: ```tsx const { architectTheme } = await import('@furystack/shades-common-components/themes/architect') themeProvider.setAssignedTheme(architectTheme) ``` ### Theme Structure A `Theme` object contains design tokens for the entire UI: - **`palette`**Semantic colors (`primary`, `secondary`, `error`, `warning`, `success`, `info`) each with `light`/`main`/`dark` variants and contrast colors - **`text`**Text colors at `primary`, `secondary`, and `disabled` emphasis levels - **`background`**Surface colors (`default`, `paper`) and an optional `paperImage` - **`button`**Button state colors (active, hover, selected, disabled) - **`typography`**Font family, size scale, weight scale, line heights, and letter spacing - **`spacing`**Spacing scale (`xs` through `xl`) - **`shape`**Border radius scale and border width - **`shadows`**Elevation presets (`none`, `sm`, `md`, `lg`, `xl`) - **`transitions`**Duration and easing presets - **`action`**Interactive state colors (hover, selected, focus ring, backdrop) - **`zIndex`**Stacking layers (drawer, appBar, modal, tooltip, dropdown) - **`effects`**Blur values for glassy surfaces ### CSS Variable System All components reference tokens through `cssVariableTheme`, which resolves to CSS custom properties (e.g. `var(--shades-theme-text-primary)`). When you call `useThemeCssVariables(theme)`, the actual theme values are written to `:root`, and all components update automatically. ```tsx import { cssVariableTheme, buildTransition } from '@furystack/shades-common-components' // Use tokens in component styles const style = { color: cssVariableTheme.text.primary, background: cssVariableTheme.background.paper, borderRadius: cssVariableTheme.shape.borderRadius.md, transition: buildTransition([ 'background', cssVariableTheme.transitions.duration.normal, cssVariableTheme.transitions.easing.default, ]), } ``` ### Creating a Custom Theme Define a palette and a theme object satisfying the `Theme` interface: ```tsx import type { Palette, Theme } from '@furystack/shades-common-components' const myPalette: Palette = { primary: { light: '#6ec6ff', lightContrast: '#000', main: '#2196f3', mainContrast: '#fff', dark: '#0069c0', darkContrast: '#fff', }, secondary: { light: '#ff79b0', lightContrast: '#000', main: '#ff4081', mainContrast: '#fff', dark: '#c60055', darkContrast: '#fff', }, error: { light: '#ff6659', lightContrast: '#000', main: '#f44336', mainContrast: '#fff', dark: '#ba000d', darkContrast: '#fff', }, warning: { light: '#ffb74d', lightContrast: '#000', main: '#ff9800', mainContrast: '#000', dark: '#f57c00', darkContrast: '#fff', }, success: { light: '#81c784', lightContrast: '#000', main: '#4caf50', mainContrast: '#fff', dark: '#388e3c', darkContrast: '#fff', }, info: { light: '#64b5f6', lightContrast: '#000', main: '#2196f3', mainContrast: '#fff', dark: '#1976d2', darkContrast: '#fff', }, } const myTheme: Theme = { name: 'my-theme', palette: myPalette, text: { primary: '#fff', secondary: 'rgba(255,255,255,0.7)', disabled: 'rgba(255,255,255,0.5)' }, // ... remaining tokens (see defaultLightTheme or defaultDarkTheme for a full reference) } ``` ## Services ### CollectionService A service for managing collections of data with pagination, sorting, and filtering. ```tsx import { CollectionService } from '@furystack/shades-common-components' const service = new CollectionService<MyModel>({ loader: async (options) => { const response = await fetch('/api/items', { /* ... */ }) return response.json() }, }) // Subscribe to data changes service.data.subscribe((items) => { console.log('Items updated:', items) }) ``` ### ThemeProviderService A singleton service for managing the active theme. It updates CSS variables and emits a `themeChanged` event so components can react to theme switches. ```tsx import { ThemeProviderService, defaultDarkTheme } from '@furystack/shades-common-components' const themeProvider = injector.get(ThemeProviderService) // Access the CSS-variable-based theme reference (for use in styles) const primaryColor = themeProvider.theme.palette.primary.main // Switch theme at runtime themeProvider.setAssignedTheme(defaultDarkTheme) // Read the currently assigned theme const current = themeProvider.getAssignedTheme() // Listen for theme changes themeProvider.subscribe('themeChanged', (theme) => { console.log('Switched to', theme.name) }) ```