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

@hyperion-framework/react-vault

v2.0.0-alpha.0

Published

React bindings for Hyperion vault.

Readme

React vault

React bindings for Hyperion vault.

Road map

Technical proof of concepts

  • Retrieval hooks
  • Selectors that have dependencies on other selectors (typed)
  • memoization of selectors
  • possible move to react-redux-hooks

Set of proof of concept Vault bindings/hooks/contexts for:

  • Collections
  • Manifest
  • Canvas
  • Annotation
  • Image service
  • VaultContext

Complete the base hooks implementation for setting up contexts and selectors and build up hook collection

  • AnnotationContext
  • AnnotationPageContext
  • CanvasContext
  • CollectionContext
  • ManifestContext
  • useAnnotation
  • useAnnotationPage
  • useCanvas
  • useCollection
  • useDispatch
  • useExternalAnnotationList
  • useExternalCollection
  • useExternalManifest
  • useManifest
  • useVault
  • useVaultEffect

Create viewer abstractions

  • SimpleViewerContext
  • SingleCanvasContext

Canvas clock implementation

  • useAnnotationsAtTime
  • useCanvasClock
  • useCanvasTimeline

Other helpers

  • RangeContext
  • usePaintingAnnotations
  • useRange
  • useSearchService
  • useVirtualCanvas

New hooks

useRenderingStrategy

There are many ways that a canvas can be rendered, some are easier than others. A hook that breaks these down into easier to render chunks will make iteratively supporting features easier.

This hook will return a type, some data and some actions. The types may be something like:

  • Single image - A single image or image service.
  • Composite image - A composition of more than one image or image service.
  • Choice - A choice that needs to be given to the user (with functions to make choice)
  • Audio - A single audio file, or sequential audio files
  • Video - A single video file, or sequential video files
  • Complex timeline - A composite of either multiple audio, video and composite images on a timeline.

This gives implementations a goal, and can easily let users know that they don't support the given canvas without an error.

The data models returned from this strategy should be similar to each other. A single image should have a way to load an image service, generate tiles or fixed sizes. Composite image should be the same as single image but with multiple. A choice should be available from the hook regardless of the type, to support a menu-like system for choices even after a choice is made. Audio and video should use a similar interface with controls. Complex timeline should be very similar to audio/video with the same controls but with additional structure similar to composite image.

type UseRenderingStrategy = {
  type: 'single-image' | 'composite-image' | 'audio' | 'video' | 'complex-timeline';
  image: { type: 'fixed-size' } | { type: 'image-service' } | null;
  images: [];
  media: { type: 'audio' } | { type: 'video' } | { type: 'sequence' };
  duration: number;
  choice: {} | null;
}

Querying and indexing


// Builds a memoized query
const filter = useFilter(() => {
  type: 'Canvas',
  id: id => id.startsWidth(`https://${myDomain}/`),
}, [myDomain]);

// The first time this is called it will build an index based on your query. (label + $contains)
const search = useVaultSearch([filter, { label: { $contains: `my-query` } }]);

//
search.results // now contains the results.

// Imperative example.
// For this filter to work, it must match reference equality.
const myFilterObject = vault.createFilter({
  type: 'Canvas',
  id: id => id.startsWidth('https://mydomain/'),
});

const myIndex = vault.createIndex({
  name: 'My index',
  refresh: true,
  filter: myFilterObject,
  indexes: ['viewingHint'],
});

// This is roughly what would be stored.
const state = {
  indexes: [
    {
      filter: myFilterObject,
      index: {
        viewingHint: {
          individuals: ['http://manifest-1/canvas-1.json'], 
          paged: ['http://manifest-1/canvas-2.json', 'http://manifest-1/canvas-3.json'],
        }
      }
    }
  ]
};

// And this is how it would be used.
const results = vault.query([myFilterObject, { 
  // This would be pre-filtered by the index.
  viewingHint: 'individuals',
  // Then this would be executed against the found objects.
  title: { $contains: 'Test' },
}]);

Vault event manager


// desired API:

const annotation = getAnnotationFromSomwehere();
const manager = useEventManager();

useEffect(() => {
  const lastAnnotation = annotation;
  const clickHandler = (e, anno) => {
    // ...
  };
  
  manager.select(lastAnnotation, 'optional-label').addEventListener('click', clickHandler);

  return () => {
    manager.select(lastAnnotation).removeEventListener('click', clickHandler);
  }
}, [annotation]);

// ...

<MyAnnotationComponent {...mananger.eventsFor(annotation)} />

// .. or

const annotationEvents = useEvents(annotation, 'optional-label');

<MyAnnotationComponent {...annotationEvents} />

// .. or

const div = useRef();

useBindEvents(div, annotation, 'optional-label');

<MyAnnotationComponent ref={div} />

Storing annotation pages

  • Annotation pages on canvases
  • Annotation pages on manifests
  • Annotation pages with manifestId in meta
  • Annotation pages with canvasId in meta

Meta

Example state:

const state = {
  meta: {
    'https://example.org/annotation-list/1': {
      annotationListManager: {
        isActive: true,
        resources: ['https://example.org/manifest-1'],
      }
    },
  }
};