srcdev-nuxt-components 9.2.6 → 9.2.7

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.
@@ -112,6 +112,8 @@ const { headingId, ariaLabelledby } = useAriaLabelledById(props.tag);
112
112
 
113
113
  /* Nested page-rows: symmetric placement by variant class */
114
114
  .page-row > .page-row {
115
+ align-content: start;
116
+
115
117
  &.full {
116
118
  grid-column: full;
117
119
  }
@@ -30,6 +30,14 @@ import type { InputTypesButton, FormUiTheme, InputButtonVariant } from "~/types/
30
30
  interface Props {
31
31
  type?: InputTypesButton;
32
32
  href?: string;
33
+ /**
34
+ * Force a real browser navigation instead of client-side routing, even for a same-origin
35
+ * href starting with "/". Needed for hrefs that aren't Vue Router pages — e.g. a Nitro
36
+ * server route like "/api/auth/github" — since NuxtLink otherwise treats any leading-"/"
37
+ * href as an internal route and does a client-side router.push, which fails silently
38
+ * (no matching route) instead of hitting the server.
39
+ */
40
+ external?: boolean;
33
41
  theme?: FormUiTheme;
34
42
  variant?: InputButtonVariant;
35
43
  isPill?: boolean;
@@ -43,6 +51,7 @@ interface Props {
43
51
  const props = withDefaults(defineProps<Props>(), {
44
52
  type: "button",
45
53
  href: undefined,
54
+ external: false,
46
55
  theme: "default",
47
56
  variant: "primary",
48
57
  isPill: false,
@@ -58,7 +67,9 @@ const NuxtLink = resolveComponent("NuxtLink");
58
67
 
59
68
  // If href is undefined tag is button, else it's a link
60
69
  const isLink = computed(() => Boolean(props.href));
61
- const isInternalLink = computed(() => isLink.value && props.href && props.href.startsWith("/"));
70
+ const isInternalLink = computed(
71
+ () => isLink.value && props.href && props.href.startsWith("/") && !props.external
72
+ );
62
73
  const tag = computed(() => {
63
74
  if (isInternalLink.value) return NuxtLink;
64
75
  if (isLink.value) return "a";
@@ -242,6 +242,34 @@ describe("InputButtonCore", () => {
242
242
  });
243
243
  });
244
244
 
245
+ // -------------------------
246
+ // Link rendering
247
+ // -------------------------
248
+ describe("Link rendering", () => {
249
+ it("renders a plain anchor for a non-internal href", async () => {
250
+ wrapper = await createWrapper({ href: "https://example.com" });
251
+ const link = wrapper.find("a");
252
+ expect(link.exists()).toBe(true);
253
+ expect(link.attributes("href")).toBe("https://example.com");
254
+ });
255
+
256
+ it("renders a real anchor with the exact href for a '/'-prefixed href when external is true", async () => {
257
+ // Regression test: InputButtonCore used to always route a leading-"/" href through
258
+ // NuxtLink (client-side router.push), which silently fails for non-page paths like a
259
+ // Nitro server route ("/api/auth/github") since no Vue Router route matches it. The
260
+ // `external` prop forces a real anchor so the browser makes an actual request instead.
261
+ wrapper = await createWrapper({ href: "/api/auth/github", external: true });
262
+ const link = wrapper.find("a");
263
+ expect(link.exists()).toBe(true);
264
+ expect(link.attributes("href")).toBe("/api/auth/github");
265
+ });
266
+
267
+ it("applies the is-link class for a link", async () => {
268
+ wrapper = await createWrapper({ href: "/api/auth/github", external: true });
269
+ expect(wrapper.find("a").classes()).toContain("is-link");
270
+ });
271
+ });
272
+
245
273
  // -------------------------
246
274
  // Computed (vm internals)
247
275
  // -------------------------
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.2.6",
4
+ "version": "9.2.7",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",