Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions docs/core/concepts/defining-drawers.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# Defining Drawers

The core package provides a framework-agnostic drawer management system that supports **extensible, type-safe custom options**. This guide shows you how to extend the base drawer configuration with your own properties to create drawers tailored to your application's needs.
The core package provides a framework-agnostic drawer management system that supports **extensible, type-safe custom options**. This guide demonstrates how to extend the base drawer configuration with custom properties to create drawers tailored to specific application requirements.

## The Concept

Every drawer in the system has a set of built-in options like `drawerKey`, `placement`, and accessibility properties. But real applications need more (you might want to pass product data, user information, or custom callbacks to your drawers).
Every drawer in the system has a set of built-in options like `drawerKey`, `placement`, and accessibility properties. However, real applications require additional capabilities, such as passing product data, user information, or custom callbacks to drawers.

The core package is designed to let you **extend** the base drawer options with any properties you need, while maintaining full type safety. Your custom fields become part of the drawer's identity and are available everywhere you interact with that drawer.
The core package supports extension of the base drawer options with arbitrary properties while maintaining full type safety. Custom fields become part of the drawer's identity and remain accessible throughout all interactions with that drawer.

## Why Extend Drawer Options?

In traditional drawer implementations, you might store drawer-related data separately from the drawer state. This creates synchronization issues and makes your code harder to maintain. By extending drawer options, you get:
In conventional drawer implementations, drawer-related data is often stored separately from the drawer state. This approach creates synchronization issues and increases maintenance complexity. Extending drawer options provides the following benefits:

**Single Source of Truth**: All data related to a drawer lives together in one place.

**Type Safety**: TypeScript ensures you never access properties that don't exist or forget required fields.
**Type Safety**: TypeScript prevents access to non-existent properties and enforces the presence of all required fields.

**Flexibility**: Add any data structure your application needs (primitives, objects, functions, etc.).
**Flexibility**: Supports arbitrary data structures including primitives, complex objects, and function references.

**Framework Independence**: The core package doesn't impose UI constraints. You define what data matters.
**Framework Independence**: The core package imposes no UI constraints, allowing developers to define application-specific data requirements.

## Extending the Base Options

Expand All @@ -33,7 +33,7 @@ The base interface provides essential drawer functionality:
- `ariaLabel`, `ariaDescribedBy`, `ariaLabelledBy`: Accessibility attributes
- `dataAttributes`: Custom data attributes for styling or testing

These options handle the mechanics of drawer behavior and accessibility. Your extensions add domain-specific data.
These options handle the mechanics of drawer behavior and accessibility. Extensions add domain-specific data.

### Creating Custom Drawer Types

Expand All @@ -43,20 +43,20 @@ To extend the base options, create an interface that extends `DrawerOptions`:
import type { DrawerOptions } from '@drawerly/core'

interface MyCustomDrawerOptions extends DrawerOptions {
// Add your custom fields here
// Add custom fields to here
title: string
data: any
onAction?: () => void
}
```

Now every drawer using `MyCustomDrawerOptions` will have both the built-in options and your custom fields.
Now every drawer using `MyCustomDrawerOptions` will have both the built-in options and defined custom fields.

## Practical Examples

### E-commerce Product Drawer

For an e-commerce application, you might need product details and purchase actions:
E-commerce applications typically require product details and purchase action handlers:

```ts
interface ProductDrawerOptions extends DrawerOptions {
Expand Down Expand Up @@ -127,7 +127,7 @@ interface NotificationDrawerOptions extends DrawerOptions {

## Creating a Typed Manager

Once you've defined your custom options, create a manager typed to those options:
After defining custom options, instantiate a manager with the appropriate type parameters:

```ts
import { createDrawerManager } from '@drawerly/core'
Expand All @@ -137,11 +137,11 @@ const userDrawers = createDrawerManager<UserDrawerOptions>()
const notificationDrawers = createDrawerManager<NotificationDrawerOptions>()
```

Each manager is now fully typed to its specific drawer type. TypeScript will enforce that you provide the correct fields when opening drawers.
Each manager instance is fully typed to its corresponding drawer type. TypeScript enforces compile-time validation, ensuring all required fields are provided when opening drawers.

## Default Options

You can set default values that apply to all drawers of a specific type:
Default values can be configured to apply to all drawers of a specific type:

```ts
const productDrawers = createDrawerManager<ProductDrawerOptions>(
Expand All @@ -151,12 +151,12 @@ const productDrawers = createDrawerManager<ProductDrawerOptions>(
placement: 'right',
closeOnEscapeKey: true,
closeOnBackdropClick: true,
inStock: true // Your custom default
inStock: true // Custom default value
}
)
```

When you open a drawer, these defaults merge with the options you provide. You only need to specify what's different:
When opening a drawer, these defaults merge with the provided options. Only values that differ from the defaults need to be specified:

```ts
productDrawers.open({
Expand All @@ -170,7 +170,7 @@ productDrawers.open({

## Dynamic Predicates

The `closeOnEscapeKey` and `closeOnBackdropClick` options can be functions that receive the drawer instance. This lets you make decisions based on your custom data:
The `closeOnEscapeKey` and `closeOnBackdropClick` options accept functions that receive the drawer instance, enabling conditional behavior based on custom data:

```ts
productDrawers.open({
Expand All @@ -180,17 +180,17 @@ productDrawers.open({
price: 2499.99,
inStock: false,

// Conditional behavior based on your custom fields
// Conditional behavior based on custom fields
closeOnEscapeKey: drawer => drawer.inStock === true,
closeOnBackdropClick: drawer => drawer.price < 1000
})
```

When the drawer is expensive or out of stock, you can prevent accidental closes by making the predicate return `false`.
For expensive or out-of-stock items, accidental closure can be prevented by configuring the predicate to return `false`.

## Type Safety in Action

TypeScript ensures your custom fields are always available and correctly typed:
TypeScript ensures custom fields remain consistently available with proper type validation:

```ts
// Opening a drawer - TypeScript requires all fields
Expand Down Expand Up @@ -225,7 +225,7 @@ productDrawers.updateOptions('product-456', current => ({

### Component-Based Drawers

If your framework uses components, you can reference them in your options:
For component-based frameworks, component references can be included in the options:

```ts
interface ComponentDrawerOptions extends DrawerOptions {
Expand Down Expand Up @@ -279,7 +279,7 @@ manager.open({
createdAt: new Date()
})

// Implement auto-close in your application code
// Implementation of auto-close behavior in application code
manager.subscribe((state) => {
state.stack.forEach((drawer) => {
if (drawer.autoCloseAfter) {
Expand All @@ -291,4 +291,4 @@ manager.subscribe((state) => {
})
```

By defining custom drawer types that extend the base `DrawerOptions`, you create a flexible, type-safe system that adapts to your application's specific needs. The drawer manager handles state management and stack operations, while your extended types ensure all the domain-specific data is properly structured and accessible throughout your application. This separation of concerns keeps your code organized and makes it easier to build complex, multi-drawer experiences.
Extending the base `DrawerOptions` with custom types creates a flexible, type-safe system that adapts to application-specific needs. The drawer manager handles state management and stack operations, while extended types maintain all domain-specific data in a properly structured and accessible format. This separation of concerns promotes code organization and simplifies the development of complex, multi-drawer experiences.
20 changes: 10 additions & 10 deletions docs/core/concepts/managing-stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ const manager = createDrawerManager<MyDrawerOptions>()

manager.open({
drawerKey: 'drawer-1',
// ... your custom options
// ... custom options
})
```

### Opening Multiple Drawers

You can open multiple drawers, and they'll stack on top of each other:
Multiple drawers can be opened, stacking on top of each other:

```ts
// First drawer opens
Expand All @@ -57,7 +57,7 @@ manager.open({

### Update Existing Drawer

If you call `open()` with a `drawerKey` that already exists, the drawer moves to the top and its options update:
When `open()` is called with an existing `drawerKey`, the drawer moves to the top and its options are updated:

```ts
// Open initial drawer
Expand Down Expand Up @@ -107,8 +107,8 @@ manager.close('drawer-2')

This is useful when:
- A background process completes
- A drawer becomes irrelevant due to user action elsewhere
- You want to close a specific drawer without affecting others
- A drawer becomes irrelevant due to user action is elsewhere
- Closing a specific drawer is required without affecting others

### Close All Drawers

Expand Down Expand Up @@ -214,7 +214,7 @@ const unsubscribe = manager.subscribe((state) => {
console.log('Stack changed!')
console.log(`Now ${state.stack.length} drawer(s) open`)

// Update your UI based on the new state
// Update the UI, based on the new state
renderDrawers(state.stack)
})

Expand All @@ -233,7 +233,7 @@ The subscription callback fires when:

### Multiple Subscribers

You can have multiple listeners for different purposes:
Multiple listeners can be registered for different purposes:

```ts
// Update the UI
Expand Down Expand Up @@ -420,7 +420,7 @@ function showNotification(id: string, message: string) {

### Limiting Stack Depth

For most applications, you should limit how many drawers can stack:
Most applications should impose limits on the number of drawers that can stack:

```ts
const MAX_STACK_DEPTH = 3
Expand Down Expand Up @@ -460,7 +460,7 @@ manager.subscribe((state) => {

**Clean Up Subscriptions**: Always unsubscribe when components unmount to prevent memory leaks.

**Batch Operations**: If you need to make multiple changes, consider using `closeAll()` and reopening rather than closing individually.
**Batch Operations**: For multiple changes, using `closeAll()` and reopening is preferable to closing individually.

**Preserve Order**: When reordering is important, use `bringToTop()` rather than closing and reopening.

Expand All @@ -475,4 +475,4 @@ if (state.stack.length > 0) {
}
```

**Communicate State**: Use the subscription system to keep your UI in sync with the drawer stack.
**Communicate State**: The subscription system should be utilized to maintain UI synchronization with the drawer stack.
20 changes: 10 additions & 10 deletions docs/core/concepts/styling.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Styling

The core package includes a complete, customizable CSS styling system. While the package is framework-agnostic and focuses on state management, it provides default styles that you can use as-is or customize to match your design system.
The core package includes a complete, customizable CSS styling system. While the package is framework-agnostic and focuses on state management, it provides default styles that can be used as-is or customized to match any design system.

## The Styling Approach

Expand All @@ -18,23 +18,23 @@ The styling system is built on:

### Import the CSS

If you're using a bundler that handles CSS imports:
When using a bundler that handles CSS imports:

```ts
import '@drawerly/core/styles.css'
```

### Link in HTML

Or include it in your HTML:
Alternatively, include it in HTML:

```html
<link rel="stylesheet" href="node_modules/@drawerly/core/dist/styles.css">
```

### Copy and Customize

For full control, copy the styles into your project and modify them directly.
For full control, the styles can be copied into the project and modified directly.

## CSS Architecture

Expand Down Expand Up @@ -89,7 +89,7 @@ The default styles define these CSS variables on `[data-drawerly-root]`:

### Basic Customization

Override variables in your own CSS:
Variables can be overridden in custom CSS:

```css
[data-drawerly-root] {
Expand Down Expand Up @@ -373,7 +373,7 @@ Make stacked drawers visible behind the top drawer:

### Internal Padding

The panel itself has no internal padding by default. Add it based on your needs:
The panel has no internal padding by default. Padding can be added as needed:

```css
[data-drawerly-panel] {
Expand Down Expand Up @@ -411,7 +411,7 @@ The panel itself has no internal padding by default. Add it based on your needs:

### Header and Footer

If your drawers have headers and footers:
For drawers with headers and footers:

```css
[data-drawerly-panel] {
Expand Down Expand Up @@ -542,11 +542,11 @@ manager.updateOptions('my-drawer', current => ({

**Use CSS Variables**: Always customize through variables first before overriding rules.

**Avoid Important**: The default styles don't use `!important`, so you shouldn't need it either.
**Avoid Important**: The default styles do not use `!important`, so it should not be necessary.

**Respect User Preferences**: The default styles include support for `prefers-reduced-motion`. Maintain this accessibility feature in your customizations.
**Respect User Preferences**: The default styles include support for `prefers-reduced-motion`. Maintain this accessibility feature in customizations.

**Z-Index Management**: If you have other overlays (modals, tooltips), ensure `--drawerly-z-index` fits your layering system.
**Z-Index Management**: When other overlays exist (modals, tooltips), ensure `--drawerly-z-index` fits the layering system.

```css
/* Example z-index hierarchy */
Expand Down
10 changes: 5 additions & 5 deletions docs/core/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Installation

Install `@drawerly/core` with your favorite package manager:
Install `@drawerly/core` with preferred package manager:

:::code-group
```bash [pnpm]
Expand All @@ -20,17 +20,17 @@ yarn add @drawerly/core

## Importing Styles

`@drawerly/core` also provives optional default styles for drawers. You can import these styles into your project as follows:
`@drawerly/core` also provives optional default styles for drawers. To import these styles into the project, add the following import statement:

```ts
import '@drawerly/core/styles.css'
```

These styles provide a basic look and feel for the drawers, but you can customize them further by overriding the CSS variables defined in the stylesheet.
These styles provide a basic look and feel for the drawers. Additional customization may be achieved by overriding the CSS variables defined in the stylesheet.

## Usage

After installation, you can start using `@drawerly/core` in your project. Let's look at a basic example of how to create a drawer manager and open a drawer:
After installation, `@drawerly/core` is ready to be used in the project. The following example demonstrates how to create a drawer manager and open a drawer:

```ts
import { createDrawerManager } from '@drawerly/core'
Expand All @@ -54,7 +54,7 @@ manager.close('example-drawer')

### Customizing Styles

You can customize the appearance of the drawers by overriding the CSS variables defined in the default stylesheet. For example, to change the background color and width of the drawers, you can add the following CSS to your project:
The appearance of drawers can be customized by overriding the CSS variables defined in the default stylesheet. The following example demonstrates how to modify the background color and dimensions of the drawers:

```css
@import '@drawerly/core/styles.css';
Expand Down
2 changes: 1 addition & 1 deletion docs/core/introduction.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Introduction

`@drawerly/core` provides a drawer stack manager with zero UI dependencies. It handles drawer state, stacking order, and lifecycle events. Framework adapters consume this package to provide UI components.
`@drawerly/core` provides a drawer stack manager with zero UI dependencies. This package manages drawer state, stacking order, and lifecycle events. Framework adapters consume this package to provide UI components.

## Key Features

Expand Down