Skip to content

Releases: pshrmn/curi

1.0.0!!!

10 Sep 05:34
Compare
Choose a tag to compare

Well, it certainly has taken a while, but I'm finally releasing Curi v1. No more breaking API changes!

This release includes @curi/router, all of the React packages, all of the route interaction packages, and all of the side effect packages. The Vue and Svelte packages still need some love, so those will go to v1 at a later date.

Quality of Life Changes

23 Apr 15:31
Compare
Choose a tag to compare
Pre-release

Breaking Changes!

While Curi is in beta, I still don't love making breaking changes. However, as it gets closer to an "official" release, there are API fixes that I would rather make now than having to wait for v2, etc.

Apologies to anyone who has to do any large rewrites because of this, but I believe that these changes will make Curi much more approachable. I do not foresee any other large changes because this covers all of the nits I had. I am confident that Curi is in a better place because of these changes, and I hope that you agree.

  1. Breaking up the match API.

The response() function is now moved to the top-level of a route and every() and initial() are grouped under the on object. on provides a better semantic grouping, especially for any future additions (on.unload()?).

// before
{
  match: {
    initial() => {...},
    every() => {...},
    response() => {...}
  }
}

// new
{
  response() => {...},
  on: {
    initial() => {...},
    every() => {...}
  }
}
  1. No more "add-ons"

"Add-on" was always a bit of a strange name for functions to interact with routes because it didn't make their purpose obvious. From now on, these functions will just be called "route interactions".

Route intearctions are accessible through the router's route property e.g. router.route.pathname("Home"). Official route interactions are moved to @curi/route- packages (@curi/route-active, @curi/route-ancestors, and @curi/route-prefetch).

Route interactions are registered with the route option array.

// old
import active from "@curi/addon-active";

const router = curi(history, routes, {
  addons: [active()]
});

// new
import active from "@curi/route-active";

const router = curi(history, routes, {
  route: [active()]
});
router.route.active("Home") // true?
  1. route.response() clean-up

Previously, route.response() functions were passed a route object with the matched route's name, parsed params, and the location. These are now passed at the top-level. route is now the object of route interactions functions (pathname() and any you include).

{
  response({ name, params, location, route }) {
    const pathname = route.pathname(name, params);
  }
}

The set methods have also been removed. Instead, route.response() should return an object. The valid properties will be merged onto the response that is emitted. Valid properties are body, error, status, title, data, and redirectTo. Most of these are copied verbatim, but redirectTo uses the name and params it is given to form a location's pathname.

{
  response() {
    return {
      body: About,
      title: "About Us"
    };
  }
}

// redirecting
{
  name: "Old Route"
  response({ params }) {
    return {
      redirectTo: {
        name: "New Route",
        params
      }
    }
}
  1. No more emitting misses

When no routes match a location, a response is not emitted. An application should always define its own catch-all route to handle these. The path string "(.*)" will match everything, so it is the easiest way to make a catch-all.

const routes = [
  // ...,
  {
    name: "Not Found",
    path: "(.*)",
    // ...
  }
];

A console warning will be called when no routes match and describe the same fix, so any issues with this should be easy to catch.

  1. No more details
    The details prop passed to the various link components never felt right. These properties (hash, query and state) are now passed directly to the link components.
// before
<Link to="Yo" details={{ hash: "ahoy" }}>Howdy</Link>

// new
<Link to="Yo" hash="ahoy">Howdy</Link>
  1. Reworked the React <Active> component and dropped <Link active>.

<Active> now takes a render-invoked children prop. That function will be given a boolean of whether or not it is "active". It will also receive the current response object as its second argument, which can be useful if you want to do additional active checks (e.g. compare query objects or hashes).

To style a <Link> as active, it should now be rendered in an <Active>'s children render-invoked prop.

<Active name="Home">
  {active => (
    <Link to="Home" className={active ? "active" : ""}>Home</Link>
  )}
</Active>

A wrapper component can be used to handle lots of links that want to be styled the same way.

const ActiveLink = ({ to, params, partial = true, ...rest }) => (
  <Active name={to} params={params} partial={partial}>
    {active => (
      <Link
        to={to}
        params={params}
        {...rest}
        className={active ? "active" : ""}
      />
    )}
  </Active>

Beta!

13 Jul 05:16
Compare
Choose a tag to compare
Beta! Pre-release
Pre-release

Curi is getting close to the point where its v1 API is finalized. Since the last release, it has switched to Hickory for its history implementation. Recently, it has also dropped middleware in favor of sideEffects (permanent subscribers). Automatic scrolling support has been added with the curi-side-effect-scroll package and you can automatically set each route page's title using the curi-side-effect-title package.

Revamped Addons

08 May 18:37
Compare
Choose a tag to compare
Revamped Addons Pre-release
Pre-release

The 0.7.0 release of the curi package has changed what route object is passed to addons. Previously, addons were passed the route object created by the user. Now, addons are passed the route object created internally by calling createRoute. This allows addons to access any properties that are created for the internal route objects, such as the keys array.

There is also a new addon package: curi-addon-active. This compares a route to the current response object and returns true when the comparison matches. The comparison is done by matching the route's name against the response's name (or sometimes the names in response.partials). If the names match, then the param are compared.

To go along with curi-addon-active, the <Link> component now supports an active prop. This allows you to style the <a> rendered by the link when the <Link> is "active".

The packaging

26 Apr 22:33
Compare
Choose a tag to compare
The packaging Pre-release
Pre-release

curi-react, et al.

curi-react has been split up into a number of smaller packages. If you want all of the React web components, you can install curi-react. However, if you only want the <Navigator> and <Link>, you may just want to install curi-react-navigator and curi-react-link.

UMD

A UMD example has been added to the curi-experiments package.

Also, UMD builds have been switched to Rollup. These builds are now slightly smaller. There is a little bit of work to do in optimizing these because there are some duplicate helpers, but the releases are still quite small. react-dom makes up the vast majority (over two-thirds) of the script download size.

file dependency of size
curi.min.js n/a 7.99kB
curi-react.min.js n/a 7.46kB
15.45kB
history.min.js curi 14.9kB
prop-types.min.js curi-react 2.42kB
32.77kB
react.min.js curi-react 21.3kB
react-dom.min.js react 129kB
183.07kB

Todo: Test Curi with Preact?

curi

The curi package has had two changes:

  1. Response objects now have a key. For browser/memory histories, this will be the same as the location's key. For hash histories, it will be a randomly generated 6 character alphanumeric string.

  2. You can now provide a cache option to createConfig. The cache allows you to re-use responses to the same location. Implementations can vary, but the cache must have get and set methods. get receives the current location and returns the cached response for the location (if one exists). set receives a response object, which the cache should store (using response.location to identify the location).

Better createConfig

20 Apr 05:25
Compare
Choose a tag to compare
Better createConfig Pre-release
Pre-release

curi

This covers both the 0.5.0 and 0.6.0 releases of curi.

Instead of exporting createConfig as a named export, the createConfig function is now the default export for curi.

Additionally, createConfig's third argument has changed. Instead of being an addons array, it is now an options object. This object currently has two valid properties: addons and middleware. The addons property is the array that used to be the third argument to createConfig. The middleware property is an array of middleware functions.

Middleware functions are functions that get called once the response object has been created, but prior to the subscriber functions being called. Middleware gives you the opportunity to modify the response that will be passed to the subscriber functions. A middleware function will receive the response object as its argument and must return a response object. The middleware functions will be called in the order they are provided in the middleware array.

curi-middleware-query

The curi-middleware-query package was created. It exports a middleware factory function, which assists in creating a middleware function that parses a response's location.search to generate a query object.

No more path()

19 Apr 17:04
Compare
Choose a tag to compare
No more path() Pre-release
Pre-release

Instead of expecting you to call the path (or parentPath) function, the route path property should now just be a (valid path-to-regexp) string.

In order to pass options to path-to-regexp, you can supply a pathOptions property to a route.

{
  name: 'Strict',
  path: 'here/',
  pathOptions: { strict: true }
}

If a route has a children property, then its path will always be created with the { end: false } option.

Little things

18 Apr 19:34
Compare
Choose a tag to compare
Little things Pre-release
Pre-release
  • Added <Link prefetch> (also, error if attempting to use prefetch without the prefetch addon)
  • Added <Link onClick>
  • Default pathname to / if <Link> is not given a name
  • Prefetch addon returns Promise.reject is attempting to get an unregistered route.

An experiment

17 Apr 17:44
Compare
Choose a tag to compare
An experiment Pre-release
Pre-release

Curi is an experiment with route configurations.

I'm becoming more confident in the API, but it is still subject to change.