svelora 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -125,10 +125,51 @@ defineConfig({
125
125
 
126
126
  ## Publish
127
127
 
128
+ Release checklist: [RELEASE_CHECKLIST.md](./RELEASE_CHECKLIST.md)
129
+
128
130
  ```bash
129
131
  bun run release:verify
130
132
  ```
131
133
 
134
+ One command publish:
135
+
136
+ ```bash
137
+ bun run public
138
+ ```
139
+
140
+ The publish command generates `CHANGELOG.md` automatically from unreleased git commits.
141
+ It groups commit messages into `Added`, `Changed`, and `Fixed`, writes the next version section, resets `## [Unreleased]` back to the template automatically, commits local changes if needed, publishes to npm, tags the release, and pushes everything.
142
+
143
+ Refresh the template manually if needed:
144
+
145
+ ```bash
146
+ bun run changelog:template
147
+ ```
148
+
149
+ Other version bumps:
150
+
151
+ ```bash
152
+ bun run public:minor
153
+ # bun run public:major
154
+ ```
155
+
156
+ Full verification before publish:
157
+
158
+ ```bash
159
+ bun run public:full
160
+ ```
161
+
162
+ Dry run:
163
+
164
+ ```bash
165
+ bun run public:dry
166
+ ```
167
+
168
+ ```bash
169
+ bun run public:minor:dry
170
+ # bun run public:major:dry
171
+ ```
172
+
132
173
  ```bash
133
174
  npm login
134
175
  npm publish --access public
@@ -1,6 +1,9 @@
1
1
  <script lang="ts" module>
2
2
  import type { LinkProps } from './link.types.js'
3
3
 
4
+ const navigationEvent = 'svelora:navigation'
5
+ let isHistoryPatched = false
6
+
4
7
  export type Props = LinkProps
5
8
 
6
9
  function parseUrl(url: string, baseUrl: URL) {
@@ -47,11 +50,64 @@
47
50
 
48
51
  return link === '/' ? current === '/' : current === link || current.startsWith(`${link}/`)
49
52
  }
53
+
54
+ function dispatchNavigationEvent() {
55
+ if (typeof window === 'undefined') {
56
+ return
57
+ }
58
+
59
+ window.dispatchEvent(new Event(navigationEvent))
60
+ }
61
+
62
+ function patchHistoryMethod(method: 'pushState' | 'replaceState') {
63
+ const historyMethod = window.history[method].bind(window.history) as (
64
+ ...args: Parameters<History['pushState']>
65
+ ) => void
66
+
67
+ Object.defineProperty(window.history, method, {
68
+ configurable: true,
69
+ value: (...args: Parameters<History['pushState']>) => {
70
+ historyMethod(...args)
71
+ dispatchNavigationEvent()
72
+ }
73
+ })
74
+ }
75
+
76
+ function ensureNavigationEvents() {
77
+ if (typeof window === 'undefined' || isHistoryPatched) {
78
+ return
79
+ }
80
+
81
+ isHistoryPatched = true
82
+ patchHistoryMethod('pushState')
83
+ patchHistoryMethod('replaceState')
84
+ }
85
+
86
+ function subscribeToLocation(callback: () => void) {
87
+ if (typeof window === 'undefined') {
88
+ return () => undefined
89
+ }
90
+
91
+ ensureNavigationEvents()
92
+
93
+ const handleLocationChange = () => callback()
94
+
95
+ handleLocationChange()
96
+ window.addEventListener('popstate', handleLocationChange)
97
+ window.addEventListener('hashchange', handleLocationChange)
98
+ window.addEventListener(navigationEvent, handleLocationChange)
99
+
100
+ return () => {
101
+ window.removeEventListener('popstate', handleLocationChange)
102
+ window.removeEventListener('hashchange', handleLocationChange)
103
+ window.removeEventListener(navigationEvent, handleLocationChange)
104
+ }
105
+ }
50
106
  </script>
51
107
 
52
108
  <script lang="ts">
109
+ import { onMount } from 'svelte'
53
110
  import { twMerge } from 'tailwind-merge'
54
- import { page } from '$app/state'
55
111
  import { getComponentConfig } from '../config.js'
56
112
  import { linkDefaults, linkVariants } from './link.variants.js'
57
113
 
@@ -80,6 +136,13 @@
80
136
  }: Props = $props()
81
137
 
82
138
  const isLink = $derived(!!href)
139
+ let currentUrl = $state<URL | undefined>(undefined)
140
+
141
+ onMount(() => {
142
+ return subscribeToLocation(() => {
143
+ currentUrl = new URL(window.location.href)
144
+ })
145
+ })
83
146
 
84
147
  const isExternal = $derived(
85
148
  isLink &&
@@ -102,14 +165,14 @@
102
165
 
103
166
  const isActive = $derived.by(() => {
104
167
  if (active !== undefined) return active
105
- if (!isLink || !page.url || isExternal) return false
168
+ if (!isLink || !currentUrl || isExternal) return false
106
169
 
107
- const link = parseUrl(href!, page.url)
170
+ const link = parseUrl(href!, currentUrl)
108
171
 
109
- if (exactHash && link.hash !== page.url.hash) return false
110
- if (!isQueryMatch(link.query, page.url.searchParams, exactQuery)) return false
172
+ if (exactHash && link.hash !== currentUrl.hash) return false
173
+ if (!isQueryMatch(link.query, currentUrl.searchParams, exactQuery)) return false
111
174
 
112
- return isPathnameMatch(link.pathname, page.url.pathname, exact)
175
+ return isPathnameMatch(link.pathname, currentUrl.pathname, exact)
113
176
  })
114
177
 
115
178
  const baseClass = $derived.by(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelora",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Modern primitive-based UI component library for Svelte 5",
5
5
  "author": "asphum",
6
6
  "license": "MIT",
@@ -28,8 +28,26 @@
28
28
  "lint:fix": "biome check --write .",
29
29
  "test:unit": "vitest",
30
30
  "test": "bun run test:unit -- --run",
31
+ "changelog:template": "node ./scripts/changelog-template.mjs",
31
32
  "release:verify": "bun run check && bun run prepack && npm pack --dry-run",
32
33
  "release:verify:full": "bun run check && bun run test && bun run prepack && npm pack --dry-run",
34
+ "release": "node ./scripts/release.mjs",
35
+ "release:patch": "node ./scripts/release.mjs patch",
36
+ "release:minor": "node ./scripts/release.mjs minor",
37
+ "release:major": "node ./scripts/release.mjs major",
38
+ "release:patch:full": "node ./scripts/release.mjs patch --full",
39
+ "release:minor:full": "node ./scripts/release.mjs minor --full",
40
+ "release:major:full": "node ./scripts/release.mjs major --full",
41
+ "release:patch:dry": "node ./scripts/release.mjs patch --dry-run",
42
+ "public": "node ./scripts/release.mjs public",
43
+ "public:minor": "node ./scripts/release.mjs public minor",
44
+ "public:major": "node ./scripts/release.mjs public major",
45
+ "public:full": "node ./scripts/release.mjs public --full",
46
+ "public:dry": "node ./scripts/release.mjs public --dry-run",
47
+ "public:minor:full": "node ./scripts/release.mjs public minor --full",
48
+ "public:major:full": "node ./scripts/release.mjs public major --full",
49
+ "public:minor:dry": "node ./scripts/release.mjs public minor --dry-run",
50
+ "public:major:dry": "node ./scripts/release.mjs public major --dry-run",
33
51
  "clean": "rm -rf dist node_modules build .svelte-kit"
34
52
  },
35
53
  "files": [