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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pol-studios/features

v1.0.9

Published

Feature modules for POL applications

Readme

@pol-studios/features

Feature modules for POL applications

Business feature modules that encapsulate common application patterns including comments, ordering, punch-lists, and filter utilities. Built on top of @pol-studios/db and @pol-studios/db/auth.

Installation

pnpm add @pol-studios/features

Peer Dependencies

pnpm add react @pol-studios/db @pol-studios/db/auth @pol-studios/utils

Quick Start

import { CommentProvider, useComments } from "@pol-studios/features/comments";
import { useOrderManager } from "@pol-studios/features/ordering";
import { usePunchListPage } from "@pol-studios/features/punch-list";
import { FilterProvider, useFilterContext } from "@pol-studios/features/filter-utils";

// Comments on any entity
function ProjectComments({ projectId }) {
  return (
    <CommentProvider entityType="project" entityId={projectId}>
      <CommentList />
    </CommentProvider>
  );
}

// Drag-and-drop ordering
function TaskList({ tasks }) {
  const { items, moveItem, saveOrder } = useOrderManager(tasks);
  // ... render sortable list
}

Subpath Exports

| Path | Description | |------|-------------| | @pol-studios/features | All exports combined | | @pol-studios/features/comments | Comment system for entities | | @pol-studios/features/ordering | Drag-and-drop ordering utilities | | @pol-studios/features/punch-list | Punch-list / checklist functionality | | @pol-studios/features/filter-utils | Filter builder utilities |

API Reference

Comments Module

Provides a complete comment system with reactions, read tracking, and quotes.

import {
  CommentProvider,
  useComments,
  CommentContext,
} from "@pol-studios/features/comments";

import type {
  CommentContextType,
  CommentWithRelations,
  Quote,
  ProfileRow,
  CoreCommentRow,
  CoreCommentReactionRow,
  CoreCommentReadRow,
  CommentProviderProps,
} from "@pol-studios/features/comments";

// Wrap component with CommentProvider
<CommentProvider
  entityType="project"
  entityId={projectId}
  userId={currentUserId}
>
  <CommentSection />
</CommentProvider>

// Use comments in child components
function CommentSection() {
  const {
    comments,           // All comments with relations
    isLoading,          // Loading state
    addComment,         // Add new comment
    updateComment,      // Edit comment
    deleteComment,      // Remove comment
    addReaction,        // React to comment
    removeReaction,     // Remove reaction
    markAsRead,         // Mark comment as read
    replyTo,            // Reply to specific comment
    quote,              // Quote text from comment
    unreadCount,        // Number of unread comments
  } = useComments();

  const handleSubmit = (text: string) => {
    addComment({ text, parentId: null });
  };

  return (
    <div>
      <div>Unread: {unreadCount}</div>
      {comments.map(comment => (
        <Comment
          key={comment.id}
          comment={comment}
          onReply={() => replyTo(comment.id)}
          onReact={(emoji) => addReaction(comment.id, emoji)}
        />
      ))}
      <CommentInput onSubmit={handleSubmit} />
    </div>
  );
}

Ordering Module

Utilities for managing item order with optimistic updates.

import {
  useOrderHint,
  useOrderManager,
} from "@pol-studios/features/ordering";

// Generate order hints for positioning
function useOrderHintExample() {
  const { generateHint, getHintBetween } = useOrderHint();

  // Get hint for inserting at position
  const hint = generateHint(index, items);

  // Get hint between two items
  const betweenHint = getHintBetween(itemA.order_hint, itemB.order_hint);
}

// Full order management
function SortableList({ initialItems }) {
  const {
    items,              // Ordered items
    moveItem,           // Move item to new position
    reorder,            // Reorder by drag-and-drop result
    saveOrder,          // Persist order to database
    isDirty,            // Has unsaved changes
    isLoading,          // Saving in progress
  } = useOrderManager(initialItems, {
    table: "tasks",
    orderColumn: "order_hint",
  });

  const handleDragEnd = (result) => {
    if (!result.destination) return;
    reorder(result.source.index, result.destination.index);
  };

  return (
    <DragDropContext onDragEnd={handleDragEnd}>
      <Droppable droppableId="list">
        {(provided) => (
          <div ref={provided.innerRef} {...provided.droppableProps}>
            {items.map((item, index) => (
              <Draggable key={item.id} draggableId={item.id} index={index}>
                {(provided) => <Item item={item} provided={provided} />}
              </Draggable>
            ))}
            {provided.placeholder}
          </div>
        )}
      </Droppable>
      <button onClick={saveOrder} disabled={!isDirty || isLoading}>
        Save Order
      </button>
    </DragDropContext>
  );
}

Punch-List Module

Punch-list / checklist page functionality for tracking items.

import { usePunchListPage } from "@pol-studios/features/punch-list";

function PunchListPage({ projectId }) {
  const {
    items,              // Punch-list items
    isLoading,          // Loading state
    filter,             // Current filter
    setFilter,          // Update filter
    stats,              // Completion statistics
    addItem,            // Add new item
    updateItem,         // Update item
    deleteItem,         // Remove item
    toggleComplete,     // Toggle item completion
    assignTo,           // Assign item to user
    groupBy,            // Grouped items (by status, assignee, etc.)
  } = usePunchListPage({
    projectId,
    defaultFilter: { status: "open" },
  });

  return (
    <div>
      <Stats total={stats.total} completed={stats.completed} />
      <FilterBar filter={filter} onChange={setFilter} />
      <ItemList
        items={items}
        onToggle={toggleComplete}
        onEdit={updateItem}
        onDelete={deleteItem}
      />
      <AddItemForm onAdd={addItem} />
    </div>
  );
}

Filter Utils Module

Utilities for building dynamic filter UIs.

import {
  FilterProvider,
  useFilterContext,
  useNestedFilterOptions,
  hookOnChange,
  getDefaultValue,
  getComparisonOptions,
  getDefaultCondition,
  genId,
  getPropertyKey,
  recurseToProperty,
  getProperty,
} from "@pol-studios/features/filter-utils";

// Wrap filter UI with provider
function FilterableList({ data, fields }) {
  return (
    <FilterProvider fields={fields}>
      <FilterBar />
      <DataList data={data} />
    </FilterProvider>
  );
}

// Build filter UI
function FilterBar() {
  const {
    filters,            // Current filter conditions
    addFilter,          // Add new filter condition
    removeFilter,       // Remove filter condition
    updateFilter,       // Update filter value
    clearFilters,       // Clear all filters
    applyFilters,       // Apply filters to data
    fields,             // Available fields to filter
  } = useFilterContext();

  return (
    <div>
      {filters.map((filter) => (
        <FilterRow
          key={filter.id}
          filter={filter}
          fields={fields}
          onUpdate={(updates) => updateFilter(filter.id, updates)}
          onRemove={() => removeFilter(filter.id)}
        />
      ))}
      <button onClick={addFilter}>Add Filter</button>
      <button onClick={clearFilters}>Clear</button>
    </div>
  );
}

// Nested filter options (for hierarchical data)
function CategoryFilter({ categories }) {
  const options = useNestedFilterOptions(categories, {
    labelKey: "name",
    valueKey: "id",
    childrenKey: "subcategories",
  });

  return <Select options={options} />;
}

// Utility functions
const comparisonOptions = getComparisonOptions("string"); // ["equals", "contains", "startsWith", ...]
const defaultValue = getDefaultValue("number"); // 0
const defaultCondition = getDefaultCondition("date"); // { operator: "equals", value: null }
const id = genId(); // Unique filter ID
const key = getPropertyKey(field); // Normalized property key
const value = getProperty(obj, "nested.path"); // Get nested value

TypeScript Types

import type {
  // Comments types
  CommentContextType,
  CommentWithRelations,
  Quote,
  ProfileRow,
  CoreCommentRow,
  CoreCommentReactionRow,
  CoreCommentReadRow,
  CommentProviderProps,
} from "@pol-studios/features/comments";

Related Packages

License

UNLICENSED