Skip to content

Commit

Permalink
proof of concept for multi-init and multi-comp
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickpatrickpatrick committed Sep 11, 2024
1 parent 78d0f40 commit 21a6103
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 14 deletions.
11 changes: 9 additions & 2 deletions packages/govuk-frontend/src/govuk/common/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,17 @@ export function setFocus($element, options = {}) {
*
* @internal
* @param {Element} $module - HTML element to be checked
* @param {string} moduleName - name of component module
* @returns {boolean} Whether component is already initialised
*/
export function isInitialised($module) {
return $module instanceof HTMLElement && 'moduleInit' in $module.dataset
export function isInitialised($module, moduleName) {
console.log('hello')
console.log($module, moduleName)

return (
$module instanceof HTMLElement &&
!!$module.getAttribute(`data-${moduleName}-init`)
)
}

/**
Expand Down
16 changes: 13 additions & 3 deletions packages/govuk-frontend/src/govuk/errors/index.jsdom.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,35 @@ describe('errors', () => {

describe('InitError', () => {
let $element
let $moduleName

beforeAll(() => {
$element = document.createElement('div')
$element.setAttribute('data-module', 'govuk-accordion')
$moduleName = 'govuk-accordion'
})

it('is an instance of GOVUKFrontendError', () => {
expect(new InitError($element)).toBeInstanceOf(GOVUKFrontendError)
expect(new InitError($moduleName)).toBeInstanceOf(GOVUKFrontendError)
})

it('has its own name set', () => {
expect(new InitError($element).name).toBe('InitError')
expect(new InitError($moduleName).name).toBe('InitError')
})

it('provides feedback for modules already initialised', () => {
expect(new InitError($element).message).toBe(
expect(new InitError($moduleName).message).toBe(
'Root element (`$module`) already initialised (`govuk-accordion`)'
)
})

it('provides feedback for modules already initialised', () => {
$moduleName = undefined

expect(new InitError($moduleName, 'Accordion').message).toBe(
'moduleName not defined in component (`Accordion`)'
)
})
})

describe('ElementError', () => {
Expand Down
14 changes: 10 additions & 4 deletions packages/govuk-frontend/src/govuk/errors/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,17 @@ export class InitError extends GOVUKFrontendError {

/**
* @internal
* @param {Element} $module - HTML element already initialised
* @param {string|undefined} moduleName - name of the component module
* @param {string} [className] - name of the component module
*/
constructor($module) {
const moduleName = $module.getAttribute('data-module')
super(`Root element (\`$module\`) already initialised (\`${moduleName}\`)`)
constructor(moduleName, className) {
let errorText = `moduleName not defined in component (\`${className}\`)`

if (typeof moduleName === 'string') {
errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`
}

super(errorText)
}
}

Expand Down
23 changes: 19 additions & 4 deletions packages/govuk-frontend/src/govuk/govuk-frontend-component.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import { InitError, SupportError } from './errors/index.mjs'
* @virtual
*/
export class GOVUKFrontendComponent {
/**
* @type {string|undefined}
*/
static moduleName
/**
* Constructs a new component, validating that GOV.UK Frontend is supported
*
Expand All @@ -20,8 +24,15 @@ export class GOVUKFrontendComponent {
this.checkSupport()
this.checkInitialised($module)

// Mark component as initialised in HTML
$module?.setAttribute('data-module-init', 'true')
const moduleName = /** @type {typeof GOVUKFrontendComponent} */ (
this.constructor
).moduleName

if (typeof moduleName === 'string') {
moduleName && $module?.setAttribute(`data-${moduleName}-init`, 'true')
} else {
throw new InitError(moduleName, this.constructor.name)
}
}

/**
Expand All @@ -32,8 +43,12 @@ export class GOVUKFrontendComponent {
* @throws {InitError} when component is already initialised
*/
checkInitialised($module) {
if ($module && isInitialised($module)) {
throw new InitError($module)
const moduleName = /** @type {typeof GOVUKFrontendComponent} */ (
this.constructor
).moduleName

if ($module && moduleName && isInitialised($module, moduleName)) {
throw new InitError(moduleName)
}
}

Expand Down
3 changes: 2 additions & 1 deletion shared/lib/names.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ module.exports = {
componentNameToMacroName,
packageResolveToPath,
packageTypeToPath,
packageNameToPath
packageNameToPath,
kebabCaseToCamelCase
}

/**
Expand Down

0 comments on commit 21a6103

Please sign in to comment.