@x-govuk/nhsuk-eleventy-plugin 1.1.2 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-govuk/nhsuk-eleventy-plugin",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Write documentation using Markdown and publish it using NHS.UK styles",
5
5
  "keywords": [
6
6
  "nhsuk",
@@ -60,6 +60,7 @@
60
60
  "@x-govuk/govuk-eleventy-plugin": "^9.0.1",
61
61
  "accessible-autocomplete": "^3.0.1",
62
62
  "deepmerge": "^4.2.2",
63
+ "highlight.js": "^11.5.0",
63
64
  "markdown-it-abbr": "^2.0.0",
64
65
  "markdown-it-anchor": "^9.0.0",
65
66
  "markdown-it-attribution": "^0.1.4",
@@ -67,19 +68,19 @@
67
68
  "markdown-it-deflist": "^3.0.0",
68
69
  "markdown-it-footnote": "^4.0.0",
69
70
  "markdown-it-github-alerts": "^1.0.0",
70
- "markdown-it-govuk": "^0.8.0",
71
+ "markdown-it-govuk": "^0.9.0",
71
72
  "markdown-it-image-figures": "^2.0.0",
72
73
  "markdown-it-ins": "^4.0.0",
73
74
  "markdown-it-mark": "^4.0.0",
74
75
  "markdown-it-sub": "^2.0.0",
75
76
  "markdown-it-sup": "^2.0.0",
76
77
  "markdown-it-table-of-contents": "^1.0.0",
77
- "nhsuk-frontend": "^10.3.0",
78
+ "nhsuk-frontend": "^10.4.2",
78
79
  "rollup": "^4.1.0",
79
80
  "sass": "^1.45.1"
80
81
  },
81
82
  "devDependencies": {
82
- "@x-govuk/eslint-config": "^0.0.1",
83
+ "@x-govuk/eslint-config": "^0.0.2",
83
84
  "@x-govuk/nhsuk-eleventy-plugin": "file:./",
84
85
  "np": "^11.0.0",
85
86
  "prettier": "^3.1.0",
@@ -87,8 +88,13 @@
87
88
  "stylelint-config-gds": "^2.0.0",
88
89
  "stylelint-order": "^7.0.0"
89
90
  },
91
+ "peerDependencies": {
92
+ "@sindresorhus/slugify": "^2.2.1",
93
+ "markdown-it": "^14.1.1",
94
+ "nunjucks": "^3.2.4"
95
+ },
90
96
  "engines": {
91
- "node": ">=22"
97
+ "node": ">=22.22"
92
98
  },
93
99
  "type": "module",
94
100
  "exports": {
@@ -1,2 +1,5 @@
1
1
  // NHS.UK Eleventy Plugin components
2
2
  @forward "pkg:@x-govuk/nhsuk-eleventy-plugin";
3
+
4
+ // Add the highlighter styles
5
+ @forward "pkg:nhsuk-frontend/lib/highlighter/styles";
@@ -1,5 +1,4 @@
1
1
  @forward "attribution";
2
- @forward "code";
3
2
  @forward "contents-list";
4
3
  @forward "footnotes-list";
5
4
  @forward "govspeak";
@@ -11,8 +11,9 @@
11
11
  <li class="nhsuk-grid-column-{{ grid }} nhsuk-card-group__item">
12
12
  {{ nhsukCard({
13
13
  clickable: item.href and params.clickable,
14
- primary: params.type == "primary",
15
- secondary: params.type == "secondary",
14
+ primary: not params.variant and params.type == "primary",
15
+ secondary: not params.variant and params.type == "secondary",
16
+ variant: params.variant,
16
17
  heading: item.heading,
17
18
  headingClasses: ("nhsuk-u-font-size-22" if params.title else "nhsuk-u-font-size-26") + (" nhsuk-u-margin-bottom-2" if item.descriptionHtml else ""),
18
19
  headingLevel: 3 if params.title else 2,
@@ -6,17 +6,6 @@
6
6
  @extend .nhsuk-contents-list__list;
7
7
  }
8
8
 
9
- // Bugfix:
10
- // Nested lists need to remove the margin at the bottom,
11
- // and add the same margin at the top as is between list items.
12
- //
13
- // This can be removed when it is fixed within NHS frontend,
14
- // see https://github.com/nhsuk/nhsuk-frontend/pull/1854
15
- .nhsuk-contents-list ol ol {
16
- @include nhsuk-responsive-margin(2, "top");
17
- margin-bottom: 0;
18
- }
19
-
20
9
  .nhsuk-contents-list li {
21
10
  // stylelint-disable-next-line scss/at-extend-no-missing-placeholder
22
11
  @extend .nhsuk-contents-list__item;
@@ -12,7 +12,6 @@ import * as sass from 'sass'
12
12
  *
13
13
  * @param {object} dir - Project directories
14
14
  * @param {object} options - Plugin options
15
- * @returns {Function} Eleventy event
16
15
  */
17
16
  export async function generateAssets(dir, options) {
18
17
  // Generate default CSS
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Render a GitHub-style alert
3
3
  *
4
- * @param {Function} md - markdown-it instance
4
+ * @param {import('markdown-it')} md - markdown-it instance
5
5
  */
6
6
  export function alertRules(md) {
7
7
  const { rules } = md.renderer
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Render a definition list
3
3
  *
4
- * @param {Function} md - markdown-it instance
4
+ * @param {import('markdown-it')} md - markdown-it instance
5
5
  */
6
6
  export function defListRules(md) {
7
7
  const { rules } = md.renderer
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Render a figure
3
3
  *
4
- * @param {Function} md - markdown-it instance
4
+ * @param {import('markdown-it')} md - markdown-it instance
5
5
  */
6
6
  export function figureRules(md) {
7
7
  const { rules } = md.renderer
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Render footnotes
3
3
  *
4
- * @param {Function} md - markdown-it instance
4
+ * @param {import('markdown-it')} md - markdown-it instance
5
5
  */
6
6
  export function footnotesRules(md) {
7
7
  const { rules } = md.renderer
@@ -0,0 +1,68 @@
1
+ import { highlighter } from 'nhsuk-frontend/lib/highlighter/index.mjs'
2
+
3
+ /**
4
+ * Highlight code using highlight.js
5
+ *
6
+ * @param {string} string - Code to highlight
7
+ * @param {string} language - Language for syntax highlighting
8
+ * @returns {string} Highlighted code HTML
9
+ */
10
+ export function highlightCode(string, language) {
11
+ const languages = language ? [language] : undefined
12
+ return highlighter.highlightAuto(string, languages).value
13
+ }
14
+
15
+ // Languages that should use the reverse (dark background) style
16
+ const reverseStyleLanguages = ['bash', 'shell', 'sh', 'zsh']
17
+
18
+ /**
19
+ * Custom fence renderer for nhsuk-frontend code component
20
+ *
21
+ * This markdown-it plugin overrides the default fence renderer to output
22
+ * HTML compatible with the nhsuk-frontend code component, including the
23
+ * copy button.
24
+ *
25
+ * @param {MarkdownIt} md - markdown-it instance
26
+ */
27
+ export default function nhsukCodePlugin(md) {
28
+ md.renderer.rules.fence = (tokens, idx) => {
29
+ const token = tokens[idx]
30
+ const language = token.info.trim()
31
+ const code = highlightCode(token.content, language)
32
+
33
+ // Check if the code block has the { .nhsuk-code--button }
34
+ // class added, to indicate that the copy button should be added.
35
+ const hasCopyButton = token.attrs?.some(
36
+ ([name, value]) =>
37
+ name === 'class' && value?.includes('nhsuk-code--button')
38
+ )
39
+
40
+ // Languages use on the command line use a reverse style
41
+ const isReverse = reverseStyleLanguages.includes(language)
42
+
43
+ // Set classes for the code block and the button
44
+ let codeClasses = 'nhsuk-code'
45
+ if (hasCopyButton) codeClasses += ' nhsuk-code--button'
46
+ if (isReverse) codeClasses += ' nhsuk-code--reverse'
47
+ const buttonClasses = isReverse
48
+ ? 'nhsuk-button nhsuk-button--reverse nhsuk-button--small nhsuk-code__button nhsuk-js-code-button'
49
+ : 'nhsuk-button nhsuk-button--secondary nhsuk-button--small nhsuk-code__button nhsuk-js-code-button'
50
+
51
+ // Output HTML compatible with nhsuk-frontend code component
52
+ let html = `<div class="${codeClasses}" data-module="nhsuk-code">\n`
53
+
54
+ // Button is hidden by default and shown by JavaScript when clipboard API is available
55
+ if (hasCopyButton) {
56
+ html += ` <button class="${buttonClasses}" data-module="nhsuk-button" type="button" hidden>Copy code</button>\n`
57
+ }
58
+
59
+ html += ` <pre class="nhsuk-code__container"><code class="nhsuk-code__content">${code}</code></pre>\n`
60
+ html += `</div>\n`
61
+
62
+ return html
63
+ }
64
+ }
65
+
66
+ /**
67
+ * @import { default as MarkdownIt } from 'markdown-it'
68
+ */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Render a table with `tabindex` to enable keyboard scrolling
3
3
  *
4
- * @param {Function} md - markdown-it instance
4
+ * @param {import('markdown-it')} md - markdown-it instance
5
5
  */
6
6
  export function tableRules(md) {
7
7
  const { rules } = md.renderer
@@ -8,7 +8,6 @@ import markdownItDeflist from 'markdown-it-deflist'
8
8
  import markdownItFootnote from 'markdown-it-footnote'
9
9
  import MarkdownItGitHubAlerts from 'markdown-it-github-alerts'
10
10
  import markdownItGovuk from 'markdown-it-govuk'
11
- import highlight from 'markdown-it-govuk/highlight'
12
11
  import markdownItImageFigures from 'markdown-it-image-figures'
13
12
  import markdownItIns from 'markdown-it-ins'
14
13
  import markdownItMark from 'markdown-it-mark'
@@ -20,6 +19,7 @@ import { alertRules } from './markdown-it/alert.js'
20
19
  import { defListRules } from './markdown-it/deflist.js'
21
20
  import { figureRules } from './markdown-it/figure.js'
22
21
  import { footnotesRules } from './markdown-it/footnote.js'
22
+ import nhsukCodePlugin from './markdown-it/highlight.js'
23
23
  import { tableRules } from './markdown-it/table.js'
24
24
 
25
25
  /**
@@ -27,12 +27,11 @@ import { tableRules } from './markdown-it/table.js'
27
27
  *
28
28
  * @see {@link https://markdown-it.github.io/markdown-it/}
29
29
  * @param {object} [markdownOptions] - Plugin Markdown options
30
- * @returns {Function} markdown-it instance
30
+ * @returns {import('markdown-it')} markdown-it instance
31
31
  */
32
32
  export function md(markdownOptions = {}) {
33
33
  const opts = {
34
34
  breaks: true,
35
- highlight,
36
35
  html: true,
37
36
  linkify: false,
38
37
  typographer: true,
@@ -46,6 +45,7 @@ export function md(markdownOptions = {}) {
46
45
  govspeak: ['blockquote', 'information-callout'],
47
46
  headingsStartWith: markdownOptions.headingsStartWith
48
47
  })
48
+ .use(nhsukCodePlugin)
49
49
  .use(markdownItAbbr)
50
50
  .use(markdownItAnchor, {
51
51
  permalink: markdownOptions.headingPermalinks
package/src/nunjucks.js CHANGED
@@ -6,10 +6,11 @@ import Nunjucks from 'nunjucks'
6
6
  * Gets the value at `path` of `object`. If the resolved value is `undefined`,
7
7
  * the `defaultValue` is returned in its place.
8
8
  *
9
+ * @template T
9
10
  * @param {object} object - Object to query
10
11
  * @param {Array|string} keys - Path of the property to get
11
- * @param {*} defaultValue - Value returned for `undefined` resolved values
12
- * @returns {*} The resolved value
12
+ * @param {T} defaultValue - Value returned for `undefined` resolved values
13
+ * @returns {T} The resolved value
13
14
  */
14
15
  function getProp(object, keys, defaultValue) {
15
16
  keys = Array.isArray(keys) ? keys : keys.split('.')
@@ -25,7 +26,7 @@ function getProp(object, keys, defaultValue) {
25
26
  *
26
27
  * @see {@link https://mozilla.github.io/nunjucks/api.html#environment}
27
28
  * @param {object} eleventyConfig - Eleventy config
28
- * @returns {Function} Nunjucks environment
29
+ * @returns {import('nunjucks').Environment} Nunjucks environment
29
30
  */
30
31
  export function nunjucksConfig(eleventyConfig) {
31
32
  const { includes, input, layouts } = eleventyConfig.dir
@@ -1,6 +1,7 @@
1
1
  @forward "pkg:nhsuk-frontend/dist/nhsuk/components/breadcrumb";
2
2
  @forward "pkg:nhsuk-frontend/dist/nhsuk/components/button";
3
3
  @forward "pkg:nhsuk-frontend/dist/nhsuk/components/card";
4
+ @forward "pkg:nhsuk-frontend/dist/nhsuk/components/code";
4
5
  @forward "pkg:nhsuk-frontend/dist/nhsuk/components/contents-list";
5
6
  @forward "pkg:nhsuk-frontend/dist/nhsuk/components/footer";
6
7
  @forward "pkg:nhsuk-frontend/dist/nhsuk/components/header";
@@ -1,153 +0,0 @@
1
- @use "../../vendor/nhsuk-frontend" as *;
2
-
3
- // Use same colour for inline code as that used on NHS.UK Digital service manual.
4
- // https://github.com/nhsuk/nhsuk-service-manual/blob/main/app/stylesheets/app/_code-highlight.scss
5
- $_code-colour: #dd1144;
6
-
7
- @include nhsuk-exports("nhsuk-eleventy-plugin/components/code") {
8
- .app-code--inline,
9
- .app-code--block {
10
- font-family: ui-monospace, monospace;
11
- -webkit-font-smoothing: auto;
12
- }
13
-
14
- .app-code--inline {
15
- background-color: nhsuk-colour("white");
16
- color: $_code-colour;
17
- font-size: 0.875em;
18
- padding: 2px nhsuk-spacing(1);
19
-
20
- a & {
21
- color: inherit;
22
- }
23
-
24
- // Ensure links within inline code blocks receive focus colour
25
- a:focus & {
26
- background: $nhsuk-focus-colour;
27
- }
28
- }
29
-
30
- .app-code--block {
31
- background-color: nhsuk-colour("white");
32
- overflow: auto;
33
- padding: nhsuk-spacing(4);
34
- scrollbar-color: nhsuk-colour("grey-1") $nhsuk-border-colour;
35
- scrollbar-width: thin;
36
-
37
- @include nhsuk-font(16, $line-height: 1.4);
38
- @include nhsuk-responsive-margin(4, "bottom");
39
-
40
- + .nhsuk-heading-l {
41
- padding-top: nhsuk-spacing(4);
42
- }
43
-
44
- + .nhsuk-heading-m,
45
- + .nhsuk-heading-s {
46
- padding-top: nhsuk-spacing(2);
47
- }
48
-
49
- &:focus {
50
- box-shadow: 0 0 0 #{$nhsuk-focus-width * 2} $nhsuk-focus-colour;
51
- outline: $nhsuk-focus-width solid nhsuk-colour("black");
52
- }
53
- }
54
-
55
- // Reverse the colour of code that uses shell highlighting
56
- .app-code__language--shell {
57
- background-color: nhsuk-colour("black");
58
- border: $nhsuk-focus-width solid nhsuk-colour("white");
59
- -webkit-font-smoothing: auto;
60
- margin-left: $nhsuk-focus-width * -1;
61
- margin-right: $nhsuk-focus-width * -1;
62
-
63
- code {
64
- filter: invert(100%);
65
- }
66
- }
67
-
68
- .app-code__comment,
69
- .app-code__quote {
70
- color: nhsuk-tint(nhsuk-colour("grey-1"), 30);
71
- font-style: italic;
72
- }
73
-
74
- .app-code__keyword,
75
- .app-code__selector-tag,
76
- .app-code__subst {
77
- color: nhsuk-colour("black");
78
- font-weight: bold;
79
- }
80
-
81
- .app-code__number,
82
- .app-code__literal,
83
- .app-code__variable,
84
- .app-code__template-variable,
85
- .app-code__tag .app-code__attr {
86
- color: nhsuk-colour("green");
87
- }
88
-
89
- .app-code__string,
90
- .app-code__doctag {
91
- color: nhsuk-colour("red");
92
- }
93
-
94
- .app-code__title,
95
- .app-code__section,
96
- .app-code__selector-id {
97
- color: nhsuk-colour("purple");
98
- font-weight: bold;
99
- }
100
-
101
- .app-code__subst {
102
- font-weight: normal;
103
- }
104
-
105
- .app-code__type,
106
- .app-code__class .app-code__title {
107
- color: nhsuk-colour("dark-pink");
108
- font-weight: bold;
109
- }
110
-
111
- .app-code__tag,
112
- .app-code__name,
113
- .app-code__attribute {
114
- color: $nhsuk-link-active-colour;
115
- font-weight: normal;
116
- }
117
-
118
- .app-code__regexp,
119
- .app-code__link {
120
- color: nhsuk-colour("green");
121
- }
122
-
123
- .app-code__symbol,
124
- .app-code__bullet {
125
- color: nhsuk-colour("purple");
126
- }
127
-
128
- .app-code__builtin,
129
- .app-code__builtin-name {
130
- color: nhsuk-colour("blue");
131
- }
132
-
133
- .app-code__meta {
134
- color: nhsuk-colour("grey-1");
135
- font-weight: bold;
136
- }
137
-
138
- .app-code__deletion {
139
- background: nhsuk-tint(nhsuk-colour("red"), 80);
140
- }
141
-
142
- .app-code__addition {
143
- background: nhsuk-tint(nhsuk-colour("green"), 80);
144
- }
145
-
146
- .app-code__emphasis {
147
- font-style: italic;
148
- }
149
-
150
- .app-code__strong {
151
- font-weight: bold;
152
- }
153
- }