@autobusal/common 1.4.6 → 1.5.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.
@@ -2,7 +2,7 @@ import { TFunction } from 'i18next';
2
2
  import { FiCalendar } from 'react-icons/fi';
3
3
  import { sanitizeHtml } from '@autobusal/utilities';
4
4
  import Image from './Image';
5
- import { LinkTitle, Details, DisplayDate, TextPreview, TextView, ButtonLink } from './styles';
5
+ import { LinkTitle, Title, Details, DisplayDate, TextPreview, TextView, ButtonLink } from './styles';
6
6
  import { ArticleData } from '@autobusal/providers/types/articles';
7
7
 
8
8
  interface Props {
@@ -13,9 +13,12 @@ interface Props {
13
13
 
14
14
  const BlogItem = ({ article, type, t }: Props): JSX.Element => (
15
15
  <div className="box">
16
- { article.image_url !== null && <Image type={ type } internal={ article.internal } image_url={ article.image_url } /> }
16
+ { article.image_url !== null && <Image type={ type } internal={ article.internal } image_url={ article.image_url } title={ article.title } /> }
17
17
 
18
- <LinkTitle to={ `/blog/article/${ article.internal }` }>{ article.title }</LinkTitle>
18
+ { type === 'view'
19
+ ? <Title>{ article.title }</Title>
20
+ : <LinkTitle to={ `/blog/article/${ article.internal }` }>{ article.title }</LinkTitle>
21
+ }
19
22
 
20
23
  <Details>
21
24
  <DisplayDate>
@@ -4,19 +4,20 @@ interface Props {
4
4
  type: 'preview' | 'view' | 'short'
5
5
  internal: string
6
6
  image_url: string
7
+ title: string
7
8
  }
8
9
 
9
- const Image = ({ type, internal, image_url }: Props): JSX.Element => {
10
+ const Image = ({ type, internal, image_url, title }: Props): JSX.Element => {
10
11
  if (type === 'preview' || type === 'short') {
11
12
  return (
12
13
  <ImageLink to={ `/blog/article/${ internal }` }>
13
- <ContainerImage src={ image_url } />
14
+ <ContainerImage src={ image_url } alt={ title } />
14
15
  </ImageLink>
15
16
  );
16
17
  }
17
18
 
18
19
  return (
19
- <ContainerImage src={ image_url } />
20
+ <ContainerImage src={ image_url } alt={ title } />
20
21
  );
21
22
  };
22
23
 
@@ -28,6 +28,14 @@ export const LinkTitle = styled(Link)`
28
28
  }
29
29
  `;
30
30
 
31
+ // Single-article view renders the title as a real <h1> instead of a
32
+ // self-link back to the same page - same visual weight as LinkTitle.
33
+ export const Title = styled.h1`
34
+ font-size: ${ props => props.theme.size.xl };
35
+ font-weight: 700;
36
+ margin: 0;
37
+ `;
38
+
31
39
  export const Details = styled.div`
32
40
  display: flex;
33
41
  gap: 15px;
package/CHANGELOG.md CHANGED
@@ -3,6 +3,34 @@
3
3
  All notable changes to `@autobusal/common` are documented here. This project follows
4
4
  [Keep a Changelog](https://keepachangelog.com/) and [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [1.5.0] - 2026-07-30
7
+
8
+ ### Fixed
9
+
10
+ - **`Meta.tsx` migrated off `react-helmet` to React 19's native document
11
+ metadata support.** react-helmet 6.1.0 (unmaintained since ~2021) was
12
+ discovered to be completely non-functional under React 19: zero of its DOM
13
+ writes were ever committing on any route, on any fresh page load, in either
14
+ consuming app - confirmed via the absence of `[data-react-helmet]` in the
15
+ DOM and by bisecting back through the app's dependency history to before
16
+ any of today's changes. Every page's `<title>`, `description`, `robots`,
17
+ `og:*`/`twitter:*` tags were silently frozen at whatever the static
18
+ `index.html` shipped, for every real user and JS-executing crawler landing
19
+ directly on a URL. `<title>`/`<meta>`/`<link>` are now rendered as plain
20
+ elements - React 19 auto-hoists and deduplicates them into `<head>` with no
21
+ library needed, and the same "deepest/last-rendered wins" semantics Helmet
22
+ was supposed to provide (a page's own `<Meta>` overriding
23
+ `@autobusal/providers`'s app-shell fallback title) now actually work.
24
+
25
+ ## [1.4.7] - 2026-07-30
26
+
27
+ ### Fixed
28
+
29
+ - **Blog thumbnails missing `alt` text (`BlogItem/Image.tsx`).** Neither the
30
+ preview/short grid thumbnail nor the full article image had `alt` - added a
31
+ required `title` prop (threaded through from `BlogItem.tsx`'s
32
+ `article.title`) used as the `alt` text on both.
33
+
6
34
  ## [1.4.6] - 2026-07-29
7
35
 
8
36
  ### Fixed
package/Meta.tsx CHANGED
@@ -1,5 +1,3 @@
1
- import { Helmet } from 'react-helmet';
2
-
3
1
  interface Props {
4
2
  title: string
5
3
  keywords?: string
@@ -21,33 +19,42 @@ const brand = import.meta.env.VITE_APP_NAME as string | undefined;
21
19
 
22
20
  const withBrand = (value: string): string => (brand ? `${ value } - ${ brand }` : value);
23
21
 
22
+ // React 19 automatically hoists any <title>/<meta>/<link> rendered ANYWHERE
23
+ // in the component tree into <head>, deduplicating <title> and meta[name=...]
24
+ // tags (last-rendered wins) - no wrapper component needed. This replaced
25
+ // react-helmet (6.1.0, unmaintained since ~2021), which had gone completely
26
+ // non-functional under React 19: none of its DOM writes were ever committing
27
+ // (verified: zero [data-react-helmet] tags in the DOM on any route, on any
28
+ // page load, even before this session's changes). Since Preload.tsx (this
29
+ // package's sibling app-shell fallback) renders its own <title> higher in the
30
+ // tree, React's last-wins dedup means whichever page's <Meta> renders here -
31
+ // deeper in the tree, so later in render order - correctly overrides it, the
32
+ // same behavior Helmet was supposed to provide but silently didn't.
24
33
  const Meta = ({ title, keywords, description, image, url, type = 'website', noIndex = false, children }: Props): JSX.Element => (
25
34
  <>
26
- <Helmet>
27
- <title>{ withBrand(title) }</title>
28
-
29
- {/* Robots */}
30
- <meta name="robots" content={ noIndex ? 'noindex, nofollow' : 'index, follow' } />
31
-
32
- {/* Standard Meta Tags */}
33
- { keywords && <meta name="keywords" content={ keywords } /> }
34
- { description && <meta name="description" content={ description } /> }
35
- { url && <link rel="canonical" href={ url } /> }
36
-
37
- {/* Open Graph / Facebook */}
38
- <meta property="og:type" content={ type } />
39
- <meta property="og:title" content={ withBrand(title) } />
40
- { description && <meta property="og:description" content={ description } /> }
41
- { image && <meta property="og:image" content={ image } /> }
42
- { url && <meta property="og:url" content={ url } /> }
43
- { brand && <meta property="og:site_name" content={ brand } /> }
44
-
45
- {/* Twitter */}
46
- <meta name="twitter:card" content="summary_large_image" />
47
- <meta name="twitter:title" content={ withBrand(title) } />
48
- { description && <meta name="twitter:description" content={ description } /> }
49
- { image && <meta name="twitter:image" content={ image } /> }
50
- </Helmet>
35
+ <title>{ withBrand(title) }</title>
36
+
37
+ {/* Robots */}
38
+ <meta name="robots" content={ noIndex ? 'noindex, nofollow' : 'index, follow' } />
39
+
40
+ {/* Standard Meta Tags */}
41
+ { keywords && <meta name="keywords" content={ keywords } /> }
42
+ { description && <meta name="description" content={ description } /> }
43
+ { url && <link rel="canonical" href={ url } /> }
44
+
45
+ {/* Open Graph / Facebook */}
46
+ <meta property="og:type" content={ type } />
47
+ <meta property="og:title" content={ withBrand(title) } />
48
+ { description && <meta property="og:description" content={ description } /> }
49
+ { image && <meta property="og:image" content={ image } /> }
50
+ { url && <meta property="og:url" content={ url } /> }
51
+ { brand && <meta property="og:site_name" content={ brand } /> }
52
+
53
+ {/* Twitter */}
54
+ <meta name="twitter:card" content="summary_large_image" />
55
+ <meta name="twitter:title" content={ withBrand(title) } />
56
+ { description && <meta name="twitter:description" content={ description } /> }
57
+ { image && <meta name="twitter:image" content={ image } /> }
51
58
 
52
59
  { children }
53
60
  </>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/common",
3
- "version": "1.4.6",
3
+ "version": "1.5.0",
4
4
  "author": "Ferjolt Ozuni",
5
5
  "type": "module",
6
6
  "main": "index.ts"