diff --git a/.prettierrc.js b/.prettierrc.js index 5bced40..ec06a8c 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,4 +1,5 @@ module.exports = { trailingComma: "all", svelteBracketNewLine: true, + proseWrap: "always", }; diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d75d7d..1ac1a21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,17 +5,23 @@ - `Router` now automatically manages focus in your app - It focuses an appropriate heading, when changing `Route`s - It makes an announcement to screen reader users when changing `Route`s - - You can customize which element should be focused after the `Route` transition via the `useFocus` hook - - You can customize the screen reader announcement via the `a11y.createAnnouncement` prop + - You can customize which element should be focused after the `Route` + transition via the `useFocus` hook + - You can customize the screen reader announcement via the + `a11y.createAnnouncement` prop - `Route`s can now be nested -- The `useParams` hook allows access to url params, matched by the parent `Route` +- The `useParams` hook allows access to url params, matched by the parent + `Route` - The `useResolvable` hook allows to subscribe to a resolved path ## Breaking: -- Link props and getProps return value will be merged, with getProps taking precedent -- Path resolution now does not treat the base of a nested Router as an absolute base any more -- The `useActiveRoute` has been removed. You should use `useMatch` or `useParams` instead +- Link props and getProps return value will be merged, with getProps taking + precedent +- Path resolution now does not treat the base of a nested Router as an absolute + base any more +- The `useActiveRoute` has been removed. You should use `useMatch` or + `useParams` instead - The `useBase` hook has been removed - The `useLinkResolve` hook has been renamed to `useResolve` @@ -51,12 +57,14 @@ ## Fixes: -- Fix incorrect resolving of links after component initialization, when using `useLinkResolve` +- Fix incorrect resolving of links after component initialization, when using + `useLinkResolve` ## Breaking: - Remove `name` prop from `Route`. Use `meta` prop instead -- Remove the apps basepath from the location, so the location always looks the same, no matter where the app is served from +- Remove the apps basepath from the location, so the location always looks the + same, no matter where the app is served from ## Other: @@ -67,15 +75,20 @@ # 1.1.0 -- Add `name` prop to `Route`, to identify a specific `Route` for example, when using the `useActiveRoute` hook -- Always keep the `route.path` intact. Use `route.fullPath` for resolved absolute path in navigation +- Add `name` prop to `Route`, to identify a specific `Route` for example, when + using the `useActiveRoute` hook +- Always keep the `route.path` intact. Use `route.fullPath` for resolved + absolute path in navigation - Use a unique id internally for matching, instead of object identity # 1.0.0 -- Expose scoped `navigate` function as prop of `Route` `component` and in slots with `let:navigate` -- Allow configuration of `Router` history through `history` prop, and exposition of `createHistory` and `createMemorySource` functions -- Allow passing of custom `navigate` function to `link` and `links` actions via `use:link={myCustomNavigate}` +- Expose scoped `navigate` function as prop of `Route` `component` and in slots + with `let:navigate` +- Allow configuration of `Router` history through `history` prop, and exposition + of `createHistory` and `createMemorySource` functions +- Allow passing of custom `navigate` function to `link` and `links` actions via + `use:link={myCustomNavigate}` - Add more examples and improve documentation # 0.4.0 @@ -92,4 +105,6 @@ - Fix link resolution -Checkout [svelte-routings Changelog](https://github.com/EmilTholin/svelte-routing/blob/master/CHANGELOG.md) for previous changes. +Checkout +[svelte-routings Changelog](https://github.com/EmilTholin/svelte-routing/blob/master/CHANGELOG.md) +for previous changes. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 43ce77b..c8ea884 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -5,31 +5,31 @@ In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +size, disability, ethnicity, sex characteristics, gender identity and +expression, level of experience, education, socio-economic status, nationality, +personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Our Responsibilities @@ -37,11 +37,11 @@ Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to ban temporarily or permanently any +contributor for other behaviors that they deem inappropriate, threatening, +offensive, or harmful. ## Scope @@ -58,8 +58,9 @@ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at michel.strelow97@gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +obligated to maintain confidentiality with regard to the reporter of an +incident. Further details of specific enforcement policies may be posted +separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other @@ -67,8 +68,9 @@ members of the project's leadership. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at +https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9190ffc..de5329b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,7 @@ ## Pull Requests -Please don't send pull requests for new features, open an issue, so we can discuss how we want to go forward. +Please don't send pull requests for new features, open an issue, so we can +discuss how we want to go forward. If you're submitting a PR, make sure to add tests for your feature/fix. @@ -40,9 +41,11 @@ yarn test ## Developing new examples - Copy the setup for one of the existing examples. -- Replace all imports from "svelte-navigator" with "../../../src", if you want to edit the Routers source for debugging purposes +- Replace all imports from "svelte-navigator" with "../../../src", if you want + to edit the Routers source for debugging purposes - Create an example and add a README for it -- Add a link to it (and if possible a link to the example running in the Svelte REPL) to the main README +- Add a link to it (and if possible a link to the example running in the Svelte + REPL) to the main README - Change all imports back to "svelte-navigator" ```bash diff --git a/README.md b/README.md index 2d826fe..d83665b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [npm]: https://img.shields.io/npm/v/svelte-navigator.svg?style=flat-square [npm-url]: https://npmjs.com/package/svelte-navigator -[example-folder-navlink]: https://github.com/mefechoeml/svelte-navigator/tree/master/example/ssr/src/components/NavLink.svelte +[example-folder-navlink]: + https://github.com/mefechoeml/svelte-navigator/tree/master/example/ssr/src/components/NavLink.svelte # Svelte Navigator @@ -11,17 +12,26 @@ > Simple, accessible routing for Svelte. -Svelte Navigator is an accessible and relatively lightweight Single Page App Router inspired by [react-router](https://github.com/ReactTraining/react-router) and [@reach/router](https://github.com/reach/router). +Svelte Navigator is an accessible and relatively lightweight Single Page App +Router inspired by [react-router](https://github.com/ReactTraining/react-router) +and [@reach/router](https://github.com/reach/router). -This started as a fork of [svelte-routing](https://github.com/EmilTholin/svelte-routing), with added configuration options and access to parts of the Routers context through React-esque hooks. +This started as a fork of +[svelte-routing](https://github.com/EmilTholin/svelte-routing), with added +configuration options and access to parts of the Routers context through +React-esque hooks. ## Features -- Accessibile routing: The `Router` manages focus in your app automatically and makes announcements to screen reader users -- Relative routing (paths and links are relative to the parent `Route` and `Router`) +- Accessible routing: The `Router` manages focus in your app automatically and + makes announcements to screen reader users +- Relative routing (paths and links are relative to the parent `Route` and + `Router`) - Nestable `Route`s for easy, flexible and reusable component composition -- Automatic route ranking: The `Router` chooses the best match automatically, so you don't need to worry about the order of your `Route`s -- Route parameters `user/:id` and (namable) wildcards `blog/*`, `blog/*wildcardName` +- Automatic route ranking: The `Router` chooses the best match automatically, so + you don't need to worry about the order of your `Route`s +- Route parameters `user/:id` and (namable) wildcards `blog/*`, + `blog/*wildcardName` - React-esque hooks api for accessing parts of the Router context - Nestable Routers for seamless merging of many smaller apps - HTML5 history mode by default (Memory mode as fallback, or for testing) @@ -54,27 +64,42 @@ This started as a fork of [svelte-routing](https://github.com/EmilTholin/svelte- ## Getting started -[example-folder-url]: https://github.com/mefechoel/svelte-navigator/tree/master/example -[example-basic-client-side]: https://github.com/mefechoel/svelte-navigator/tree/master/example/basic-client-side -[example-custom-hash-history]: https://github.com/mefechoel/svelte-navigator/tree/master/example/custom-hash-history -[example-private-routes]: https://github.com/mefechoel/svelte-navigator/tree/master/example/private-routes -[example-lazy-loading]: https://github.com/mefechoel/svelte-navigator/tree/master/example/lazy-loading -[example-ssr]: https://github.com/mefechoel/svelte-navigator/tree/master/example/ssr -[example-url-bar]: https://github.com/mefechoel/svelte-navigator/tree/master/example/url-bar -[repl-basic-client-side]: https://svelte.dev/repl/451fd183e0d3403cb7800101f7d799fb -[repl-custom-hash-history]: https://svelte.dev/repl/195011a49a714e22b1a335037e124458 +[example-folder-url]: + https://github.com/mefechoel/svelte-navigator/tree/master/example +[example-basic-client-side]: + https://github.com/mefechoel/svelte-navigator/tree/master/example/basic-client-side +[example-custom-hash-history]: + https://github.com/mefechoel/svelte-navigator/tree/master/example/custom-hash-history +[example-private-routes]: + https://github.com/mefechoel/svelte-navigator/tree/master/example/private-routes +[example-lazy-loading]: + https://github.com/mefechoel/svelte-navigator/tree/master/example/lazy-loading +[example-ssr]: + https://github.com/mefechoel/svelte-navigator/tree/master/example/ssr +[example-url-bar]: + https://github.com/mefechoel/svelte-navigator/tree/master/example/url-bar +[repl-basic-client-side]: + https://svelte.dev/repl/451fd183e0d3403cb7800101f7d799fb +[repl-custom-hash-history]: + https://svelte.dev/repl/195011a49a714e22b1a335037e124458 [repl-private-routes]: https://svelte.dev/repl/c81d8f3dff584065a82b2d3ea7cd4aee [repl-lazy-loading]: https://svelte.dev/repl/09abb8c287f745169f66f62d51f766d5 [repl-url-bar]: https://svelte.dev/repl/dc82bb89447647edb0d7ed8cbe7999ae -Look at the [example folder][example-folder-url] for a few example project setups, or checkout the examples in the Svelte REPL: - -- Simple basic usage in a client side rendered app ([examples][example-basic-client-side], [REPL][repl-basic-client-side]) -- Private Routes for authenticated users only ([examples][example-private-routes], [REPL][repl-private-routes]) -- Using Routes to lazy load views ([examples][example-lazy-loading], [REPL][repl-lazy-loading]) -- Reacting to changes in location using `useLocation` ([examples][example-url-bar], [REPL][repl-url-bar]) +Look at the [example folder][example-folder-url] for a few example project +setups, or checkout the examples in the Svelte REPL: + +- Simple basic usage in a client side rendered app + ([examples][example-basic-client-side], [REPL][repl-basic-client-side]) +- Private Routes for authenticated users only + ([examples][example-private-routes], [REPL][repl-private-routes]) +- Using Routes to lazy load views ([examples][example-lazy-loading], + [REPL][repl-lazy-loading]) +- Reacting to changes in location using `useLocation` + ([examples][example-url-bar], [REPL][repl-url-bar]) - SSR ([examples][example-ssr]) -- Using hash based navigation with a custom history ([examples][example-custom-hash-history], [REPL][repl-custom-hash-history]) +- Using hash based navigation with a custom history + ([examples][example-custom-hash-history], [REPL][repl-custom-hash-history]) ## Installation @@ -124,8 +149,9 @@ Basic Setup for a client-side SPA: ``` -Svelte Navigator uses the HTML5 History API by default. For it to work properly, you need to setup your server correctly. -If you're using sirv, as is common with a lot of Svelte projects, you need to pass it the `--single` option. +Svelte Navigator uses the HTML5 History API by default. For it to work properly, +you need to setup your server correctly. If you're using sirv, as is common with +a lot of Svelte projects, you need to pass it the `--single` option. You can read more about the History API here: @@ -159,7 +185,10 @@ The main elements to configure and use routing in your Svelte app. #### `Router` -The `Router` component supplies the `Link` and `Route` descendant components with routing information through context, so you need at least one `Router` at the top of your application. It assigns a score to all its `Route` descendants and picks the best match to render. +The `Router` component supplies the `Link` and `Route` descendant components +with routing information through context, so you need at least one `Router` at +the top of your application. It assigns a score to all its `Route` descendants +and picks the best match to render. ```html @@ -170,9 +199,12 @@ The `Router` component supplies the `Link` and `Route` descendant components wit ``` -The `Router` will automatically manage focus in your app. When you change `Route`s, it will focus the first heading in the matched `Route`. +The `Router` will automatically manage focus in your app. When you change +`Route`s, it will focus the first heading in the matched `Route`. -If you have multiple `Router`s, for example one for a navigation bar and one for the main content, make sure to pass `primary={false}` to all `Router`s, you don't want to manage focus (in this case the nav `Router`). +If you have multiple `Router`s, for example one for a navigation bar and one for +the main content, make sure to pass `primary={false}` to all `Router`s, you +don't want to manage focus (in this case the nav `Router`). ```html @@ -190,11 +222,17 @@ If you have multiple `Router`s, for example one for a navigation bar and one for ``` -If you want to focus a different element, like a skip-navigtion-link or an info text, you can use the `useFocus` hook, to specify a custom focus element. +If you want to focus a different element, like a skip-navigtion-link or an info +text, you can use the `useFocus` hook, to specify a custom focus element. -Svelte navigator also announces navigations to a screen reader. You can customize its message (i.e. for localization) via the `a11y.createAnnouncement` prop. +Svelte navigator also announces navigations to a screen reader. You can +customize its message (i.e. for localization) via the `a11y.createAnnouncement` +prop. -If you're interested in accessibility concerns in SPA routers you can check out [this article](https://www.gatsbyjs.org/blog/2019-07-11-user-testing-accessible-client-routing/), which provided much of the information, regarding focus management, used for implementing Svelte Navigators focus management. +If you're interested in accessibility concerns in SPA routers you can check out +[this article](https://www.gatsbyjs.org/blog/2019-07-11-user-testing-accessible-client-routing/), +which provided much of the information, regarding focus management, used for +implementing Svelte Navigators focus management. ```html @@ -241,7 +279,9 @@ If you're interested in accessibility concerns in SPA routers you can check out Yeah, Routing! ``` -`Router` components can also be nested to allow for seamless merging of many smaller apps. Just make sure not to forget the wildcard (`*`) in the parent `Route`s path. +`Router` components can also be nested to allow for seamless merging of many +smaller apps. Just make sure not to forget the wildcard (`*`) in the parent +`Route`s path. It's probably easier to nest `Route`s though. @@ -269,9 +309,10 @@ It's probably easier to nest `Route`s though. ``` -When you are serving your app from a subdirectory on your server, you can add a `basepath` prop to the router. -It will be prepended to all routes and to all resolved navigations (i.e. using `Link`, `useNavigate` or `useResolve`). -A `basepath` should have a leading, but no trailing slash. +When you are serving your app from a subdirectory on your server, you can add a +`basepath` prop to the router. It will be prepended to all routes and to all +resolved navigations (i.e. using `Link`, `useNavigate` or `useResolve`). A +`basepath` should have a leading, but no trailing slash. ```html @@ -282,7 +323,13 @@ A `basepath` should have a leading, but no trailing slash. ``` -By default `Router`s use the HTML5 history API for navigation. You can provide a different history through the `history` prop. Svelte Navigator ships with a memory based history, which is used, when the application does not seem to run in a browser (i.e. in a test environment) or in an embedded page, like the Svelte REPL. You can explicitly set the memory history or you can provide your own implementation (for example a [Hash based history][example-custom-hash-history]). +By default `Router`s use the HTML5 history API for navigation. You can provide a +different history through the `history` prop. Svelte Navigator ships with a +memory based history, which is used, when the application does not seem to run +in a browser (i.e. in a test environment) or in an embedded page, like the +Svelte REPL. You can explicitly set the memory history or you can provide your +own implementation (for example a [Hash based +history][example-custom-hash-history]). ```html ``` -The returned `navigate` function accepts the same parameters as the global [`navigate`](#navigate) function. +The returned `navigate` function accepts the same parameters as the global +[`navigate`](#navigate) function. ###### Parameters @@ -581,7 +652,8 @@ The returned `navigate` function accepts the same parameters as the global [`nav #### `useLocation` -Access the current location via a readable store and react to changes in location. +Access the current location via a readable store and react to changes in +location. ```html @@ -604,8 +676,10 @@ Access the current location via a readable store and react to changes in locatio #### `useResolve` -Resolve a given link relative to the current `Route` and the `Router`s `basepath`. It is used under the hood in `Link` and `useNavigate`. -You can use it to manually resolve links, when using the `link` or `links` actions. (See [`link`](#link-1)) +Resolve a given link relative to the current `Route` and the `Router`s +`basepath`. It is used under the hood in `Link` and `useNavigate`. You can use +it to manually resolve links, when using the `link` or `links` actions. (See +[`link`](#link-1)) ```html

Don't worry about me...

-

Here, look at me!

+

Here, look at me!

``` You can also use `registerFocus` asyncronously: @@ -751,11 +828,13 @@ You can also use `registerFocus` asyncronously: const registerFocus = useFocus(); - const lazyImport = import("./MyComponent.svelte").then(module => module.default); + const lazyImport = import("./MyComponent.svelte").then( + module => module.default, + ); {#await lazyImport then MyComponent} - + {/await} @@ -766,10 +845,10 @@ You can also use `registerFocus` asyncronously:

Hi there!

``` -You should however only use it asyncronously, if you KNOW, that the focus element -will register soon. Otherwise, focus will remain at the clicked link, and randomly -change a few seconds later without explanation, which is a very bad experience for -screen reader users. +You should however only use it asyncronously, if you KNOW, that the focus +element will register soon. Otherwise, focus will remain at the clicked link, +and randomly change a few seconds later without explanation, which is a very bad +experience for screen reader users. When you need to wait for data, before you can render a component, you should consider providing a hidden heading, that informs a screen reader user about the @@ -801,31 +880,41 @@ current loading process. {#await blogPostRequest} -

- The blog post is being loaded... -

+

+ The blog post is being loaded... +

{:then data} - + {/await} ``` ### Programmatic Navigation -Svelte Navigator exports a global `navigate` function, you can use to programmatically navigate around your application. +Svelte Navigator exports a global `navigate` function, you can use to +programmatically navigate around your application. -It will however not be able to perform relative navigation. Use the `useNavigate` hook instead. +It will however not be able to perform relative navigation. Use the +`useNavigate` hook instead. -If your using a custom history (for example with `createMemorySource`), the created history will have its own `navigate` function. Calling the globally exported function, will not work as intended. +If your using a custom history (for example with `createMemorySource`), the +created history will have its own `navigate` function. Calling the globally +exported function, will not work as intended. -If you're serving your app from a subdirectory or if you're using a custom history, it is not advised to use `navigate`. Use `useNavigate` instead. +If you're serving your app from a subdirectory or if you're using a custom +history, it is not advised to use `navigate`. Use `useNavigate` instead. #### `navigate` -A function that allows you to imperatively navigate around the application for those use cases where a `Link` component is not suitable, e.g. after submitting a form. +A function that allows you to imperatively navigate around the application for +those use cases where a `Link` component is not suitable, e.g. after submitting +a form. -The first argument is a string denoting where to navigate to, and the second argument is an object with a `replace` and `state` property equivalent to those in the `Link` component. +The first argument is a string denoting where to navigate to, and the second +argument is an object with a `replace` and `state` property equivalent to those +in the `Link` component. -Note that `navigate` does not have access to the Routers context, so it cannot automatically resolve relative links. You might prefer `useNavigate` instead. +Note that `navigate` does not have access to the Routers context, so it cannot +automatically resolve relative links. You might prefer `useNavigate` instead. ```html ``` -If the first parameter to `navigate` is a number, it is used to navigate the history stack (for example for a browser like "go back/go forward" functionality). +If the first parameter to `navigate` is a number, it is used to navigate the +history stack (for example for a browser like "go back/go forward" +functionality). ```html