Skip to content

Commit

Permalink
Merge pull request #1215 from daniel-ac-martin/search-box
Browse files Browse the repository at this point in the history
Add SearchBox component and allow form-actions to be configured
  • Loading branch information
daniel-ac-martin authored Dec 10, 2024
2 parents 469fdfb + 73bea9c commit 5f633b7
Show file tree
Hide file tree
Showing 39 changed files with 948 additions and 21 deletions.
2 changes: 2 additions & 0 deletions .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ module.exports = {
'../components/panel/spec/*.stories.@(js|mdx)',
'../components/phase-banner/spec/*.stories.@(js|mdx)',
'../components/radios/spec/*.stories.@(js|mdx)',
'../components/search-box/spec/*.stories.@(js|mdx)',
'../components/select/spec/*.stories.@(js|mdx)',
'../components/skip-link/spec/*.stories.@(js|mdx)',
'../components/standalone-input/spec/*.stories.@(js|mdx)',
'../components/table/spec/*.stories.@(js|mdx)',
'../components/tabs/spec/*.stories.@(js|mdx)',
'../components/tag/spec/*.stories.@(js|mdx)',
Expand Down
4 changes: 3 additions & 1 deletion apps/govuk-docs/src/common/stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ const unofficialStories = [
require('../../../../components/form/spec/Form.stories.mdx'),
require('../../../../components/form-field/spec/FormField.stories.mdx'),
require('../../../../components/navigation-menu/spec/NavigationMenu.stories.mdx'),
require('../../../../components/page/spec/Page.stories.mdx')
require('../../../../components/page/spec/Page.stories.mdx'),
require('../../../../components/search-box/spec/SearchBox.stories.mdx'),
require('../../../../components/standalone-input/spec/StandaloneInput.stories.mdx')
];
const internalStories = [
require('../../../../components/button-group/spec/ButtonGroup.stories.mdx'),
Expand Down
3 changes: 2 additions & 1 deletion apps/govuk-docs/src/server/httpd.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { resolve } from 'path';
import engine, { Handler, Mode } from '@not-govuk/engine';
import engine, { cspSelf, Handler, Mode } from '@not-govuk/engine';
import config from './config';
import AppWrap from '../common/app-wrap';
import ErrorPage from '../common/error-page';
Expand Down Expand Up @@ -27,6 +27,7 @@ export const createServer = ({ entrypoints, port }: httpdOptions) => {
secure: config.cookies.secure
},
env: config.env,
formAction: [ 'www.google.co.uk', cspSelf ],
httpd: {
host: config.httpd.host,
port: port || config.httpd.port
Expand Down
7 changes: 2 additions & 5 deletions apps/govuk-template/src/common/pages/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@ const Page: FC<PageProps> = () => {

return (
<Fragment>
<h1>Search</h1>
<Form action="?" method="get" initialValues={{ q: location.query['q'] }}>
<Form.TextInput
name="q"
label={<h2>Search</h2>}
/>
<Form.Submit>Search</Form.Submit>
<Form.SearchBox name="q" className="govuk-!-width-two-thirds" />
</Form>
<div className="width-one-half" style={{ float: 'left' }}>
<h2>Result</h2>
Expand Down
7 changes: 7 additions & 0 deletions components/error-message/assets/ErrorMessage.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
@import "@not-govuk/sass-base";
@import "govuk-frontend/dist/govuk/components/error-message/index";
@import "govuk-frontend/dist/govuk/utilities/_visually-hidden";

.govuk-error-message {
&--hidden {
@extend .govuk-visually-hidden;
}
}
16 changes: 14 additions & 2 deletions components/error-message/src/ErrorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,25 @@ import '../assets/ErrorMessage.scss';

export type ErrorMessageProps = StandardProps & HTMLAttributes<HTMLParagraphElement> & {
children?: ReactNode
hidden?: boolean
};

export const ErrorMessage: FC<ErrorMessageProps> = ({ children, classBlock, classModifiers, className, ...attrs }) => {
export const ErrorMessage: FC<ErrorMessageProps> = ({
children,
classBlock,
classModifiers: _classModifiers = [],
className,
hidden = false,
...attrs
}) => {
const classModifiers = [
hidden ? 'hidden' : undefined,
...(Array.isArray(_classModifiers) ? _classModifiers : [_classModifiers])
];
const classes = classBuilder('govuk-error-message', classBlock, classModifiers, className);

return (
<p {...attrs} className={classes()}>
<p {...attrs} className={classes()} aria-hidden={hidden}>
<VisuallyHidden>Error:</VisuallyHidden> {children}
</p>
);
Expand Down
9 changes: 9 additions & 0 deletions components/form-group/assets/FormGroup.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
@import "@not-govuk/sass-base";
@import "govuk-frontend/dist/govuk/objects/_form-group";

.govuk-form-group {
&--standalone {
&.govuk-form-group--error {
padding-left: 0;
border-left-width: 0;
}
}
}
11 changes: 7 additions & 4 deletions components/form-group/src/FormGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC, Fragment, HTMLAttributes, ReactNode, createElement as h } from 'react';
import { StandardProps, classBuilder } from '@not-govuk/component-helpers';
import { ErrorMessage } from '@not-govuk/error-message';
import { FieldSet, FieldSetProps } from '@not-govuk/fieldset';
import { FieldSet } from '@not-govuk/fieldset';
import { Hint } from '@not-govuk/hint';
import { Label } from '@not-govuk/label';

Expand All @@ -16,6 +16,7 @@ export type FormGroupProps = StandardProps & Omit<HTMLAttributes<HTMLDivElement>
hintId?: string
id: string
label: ReactNode
standalone?: boolean
};

export const FormGroup: FC<FormGroupProps> = ({
Expand All @@ -30,10 +31,12 @@ export const FormGroup: FC<FormGroupProps> = ({
hintId: _hintId,
id,
label,
standalone = false,
...attrs
}) => {
const classModifiers = [
error ? 'error' : undefined,
standalone ? 'standalone' : undefined,
...(Array.isArray(_classModifiers) ? _classModifiers : [_classModifiers])
];
const classes = classBuilder('govuk-form-group', classBlock, classModifiers, className);
Expand All @@ -49,8 +52,8 @@ export const FormGroup: FC<FormGroupProps> = ({

const children = (
<Fragment>
{ !hint ? null : <Hint id={hintId}>{hint}</Hint> }
{ !error ? null : <ErrorMessage id={errorId}>{error}</ErrorMessage>}
{ !hint ? null : <Hint id={hintId} hidden={standalone}>{hint}</Hint> }
{ !error ? null : <ErrorMessage id={errorId} hidden={standalone}>{error}</ErrorMessage> }
{_children}
</Fragment>
);
Expand All @@ -59,7 +62,7 @@ export const FormGroup: FC<FormGroupProps> = ({
<div id={id} {...attrs} className={classes()}>
{ fieldId ? (
<Fragment>
<Label htmlFor={fieldId}>{label}</Label>
<Label htmlFor={fieldId} hidden={standalone}>{label}</Label>
{children}
</Fragment>
) : (
Expand Down
2 changes: 2 additions & 0 deletions components/form/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
"@not-govuk/form-field": "workspace:^0.15.1",
"@not-govuk/forms": "workspace:^0.15.1",
"@not-govuk/radios": "workspace:^0.15.1",
"@not-govuk/search-box": "workspace:^0.15.1",
"@not-govuk/select": "workspace:^0.15.1",
"@not-govuk/standalone-input": "workspace:^0.15.1",
"@not-govuk/text-input": "workspace:^0.15.1",
"@not-govuk/textarea": "workspace:^0.15.1"
},
Expand Down
6 changes: 6 additions & 0 deletions components/form/src/Form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import {
DateInput,
Field,
Radios,
SearchBox,
Select,
StandaloneInput,
TextInput,
Textarea
} from './fields';
Expand All @@ -28,8 +30,10 @@ type TForm = ComponentType<FormProps> & {
Fork: ComponentType<any>
Page: ComponentType<any>
Radios: ComponentType<any>
SearchBox: ComponentType<any>
Select: ComponentType<any>
Submit: ComponentType<any>
StandaloneInput: ComponentType<any>
TextInput: ComponentType<any>
Textarea: ComponentType<any>
};
Expand All @@ -48,7 +52,9 @@ export const Form: TForm = Object.assign(
Fork,
Page,
Radios,
SearchBox,
Select,
StandaloneInput,
Submit,
TextInput,
Textarea
Expand Down
4 changes: 4 additions & 0 deletions components/form/src/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { Checkboxes as _Checkboxes, CheckboxesProps } from '@not-govuk/checkboxe
import { DateInput as _DateInput, DateInputProps } from '@not-govuk/date-input';
import { FormField as _Field, FormFieldProps } from '@not-govuk/form-field';
import { Radios as _Radios, RadiosProps } from '@not-govuk/radios';
import { SearchBox as _SearchBox, SearchBoxProps } from '@not-govuk/search-box';
import { Select as _Select, SelectProps } from '@not-govuk/select';
import { StandaloneInput as _StandaloneInput, StandaloneInputProps } from '@not-govuk/standalone-input';
import { TextInput as _TextInput, TextInputProps } from '@not-govuk/text-input';
import { Textarea as _Textarea, TextareaProps } from '@not-govuk/textarea';

Expand All @@ -16,6 +18,8 @@ export const DateInput: ComponentType<DateInputProps & FieldProps> = withForm(_D
});
export const Field: ComponentType<FormFieldProps & FieldProps> = withForm(_Field as any);
export const Radios: ComponentType<RadiosProps & FieldProps> = withForm(_Radios);
export const SearchBox: ComponentType<SearchBoxProps & FieldProps> = withForm(_SearchBox);
export const Select: ComponentType<SelectProps & FieldProps> = withForm(_Select);
export const StandaloneInput: ComponentType<StandaloneInputProps & FieldProps> = withForm(_StandaloneInput);
export const TextInput: ComponentType<TextInputProps & FieldProps> = withForm(_TextInput);
export const Textarea: ComponentType<TextareaProps & FieldProps> = withForm(_Textarea);
7 changes: 7 additions & 0 deletions components/hint/assets/Hint.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
@import "@not-govuk/sass-base";
@import "govuk-frontend/dist/govuk/components/hint/index";
@import "govuk-frontend/dist/govuk/utilities/_visually-hidden";

.govuk-hint {
&--hidden {
@extend .govuk-visually-hidden;
}
}

// Global override
.hint {
Expand Down
16 changes: 14 additions & 2 deletions components/hint/src/Hint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@ import '../assets/Hint.scss';

export type HintProps = StandardProps & HTMLAttributes<HTMLDivElement> & {
children?: ReactNode
hidden?: boolean
};

export const Hint: FC<HintProps> = ({ children, classBlock, classModifiers, className, ...attrs }) => {
export const Hint: FC<HintProps> = ({
children,
classBlock,
classModifiers: _classModifiers = [],
className,
hidden = false,
...attrs
}) => {
const classModifiers = [
hidden ? 'hidden' : undefined,
...(Array.isArray(_classModifiers) ? _classModifiers : [_classModifiers])
];
const classes = classBuilder('govuk-hint', classBlock, classModifiers, className);

return (
<div {...attrs} className={classes()}>{children}</div>
<div {...attrs} className={classes()} aria-hidden={hidden}>{children}</div>
);
};

Expand Down
5 changes: 5 additions & 0 deletions components/label/assets/Label.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import "@not-govuk/sass-base";
@import "govuk-frontend/dist/govuk/components/label/index";
@import "govuk-frontend/dist/govuk/utilities/_visually-hidden";

.govuk-label {
h1, h2, h3, h4, h5, h6 {
Expand All @@ -26,6 +27,10 @@
@extend .govuk-label--s;
margin-bottom: govuk-spacing(1);
}

&--hidden {
@extend .govuk-visually-hidden;
}
}

// Global override
Expand Down
16 changes: 14 additions & 2 deletions components/label/src/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@ import '../assets/Label.scss';

export type LabelProps = StandardProps & LabelHTMLAttributes<HTMLLabelElement> & {
children?: ReactNode
hidden?: boolean
};

export const Label: FC<LabelProps> = ({ children, classBlock, classModifiers, className, ...attrs }) => {
export const Label: FC<LabelProps> = ({
children,
classBlock,
classModifiers: _classModifiers = [],
className,
hidden = false,
...attrs
}) => {
const classModifiers = [
hidden ? 'hidden' : undefined,
...(Array.isArray(_classModifiers) ? _classModifiers : [_classModifiers])
];
const classes = classBuilder('govuk-label', classBlock, classModifiers, className);

return (
<label {...attrs} className={classes()}>{children}</label>
<label {...attrs} className={classes()} aria-hidden={hidden}>{children}</label>
);
};

Expand Down
5 changes: 5 additions & 0 deletions components/search-box/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dist/
node_modules/
package-lock.json
pnpm-lock.yaml
tsconfig.tsbuildinfo
71 changes: 71 additions & 0 deletions components/search-box/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
NotGovUK - Search Box
=====================

A single-line, form field for searching, with submit button.

(Heavily inspired by the [Search component] in the [GOV.UK Component Guide].)

Using this package
------------------

First install the package into your project:

```shell
npm install -S @not-govuk/search-box
```

Then use it in your code as follows:

```js
import React, { createElement as h } from 'react';
import SearchBox from '@not-govuk/search-box';

export const MyComponent = props => (
<form method="get" action="https://www.google.co.uk/search">
<SearchBox name="q" label="Search Google" width={15} />
</form>
);

export default MyComponent;
```


Working on this package
-----------------------

Before working on this package you must install its dependencies using
the following command:

```shell
pnpm install
```


### Testing

Run the unit tests.

```shell
npm test
```


### Building

Build the package by compiling the TypeScript source code.

```shell
npm run build
```


### Clean-up

Remove any previously built files.

```shell
npm run clean
```

[Search component]: https://components.publishing.service.gov.uk/component-guide/search
[GOV.UK Component Guide]: https://components.publishing.service.gov.uk/component-guide
Loading

1 comment on commit 5f633b7

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Published on https://not-gov.uk as production
🚀 Deployed on https://6758b154afa27477535c5e67--notgovuk.netlify.app

Please sign in to comment.