diff --git a/plop-templates/radio-group/component.json b/plop-templates/radio-group/component.json new file mode 100644 index 0000000..032fa4f --- /dev/null +++ b/plop-templates/radio-group/component.json @@ -0,0 +1,32 @@ +{ + "component": "radio-group", + "properties": { + "name": { + "type": "string", + "required": true, + "storyDefault": "radio-group-1" + }, + "label": { + "type": "string", + "required": true, + "storyDefault": "Radio Group Label" + }, + "options": { + "customType": "RadioGroupOptions", + "type": "Object", + "required": true, + "storyDefault": { + "option 1": "Option 1", + "option 2": "Option 2" + } + }, + "disabled": { + "type": "boolean", + "default": false + }, + "hiddenLabel": { + "type": "boolean", + "default": false + } + } +} diff --git a/plop-templates/radio-group/component.stories.ts b/plop-templates/radio-group/component.stories.ts new file mode 100644 index 0000000..6580c73 --- /dev/null +++ b/plop-templates/radio-group/component.stories.ts @@ -0,0 +1,24 @@ +import type { StoryObj, Meta } from "@storybook/web-components"; + +import { + {{#each variants}} + Input{{ singularize (titleCase @key) }}, + {{/each}} +} from "./component"; +import "./component"; + +const meta: Meta = { + component: "{{meta.prefix}}-{{name}}", + argTypes: { + {{> storybookVariantControls }} + {{> storybookControls}} + }, +}; + +export default meta; + +export const Default: StoryObj = { + args: { + {{> storybookArgs }} + } +}; diff --git a/plop-templates/radio-group/component.styles.ts b/plop-templates/radio-group/component.styles.ts new file mode 100644 index 0000000..918a928 --- /dev/null +++ b/plop-templates/radio-group/component.styles.ts @@ -0,0 +1,65 @@ +import { css } from "lit" + +export const radioGroupStyles = css` + .radio-group { + display: flex; + flex-direction: column; + gap: var(--space-small); + } + + .radio-group--heading { + font-size: var(--ds-default-font-size); + font-family: var(--ds-default-font); + } + + .radio { + position: relative; + } + + .radio--label { + display: inline-flex; + align-items: center; + gap: var(--space-small); + position: relative; + padding-inline-start: calc(var(--space-medium) * 2); + color: var(--color-primary-700); + cursor: pointer; + } + + .radio--icon { + display: none; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + } + + .radio--label::before, + .radio--label::after { + content: ""; + position: absolute; + z-index: var(--zLayer-default, 1); + } + + .radio--label::before { + inset-inline-start: 0; + inline-size: 20px; + block-size: 20px; + border: 2px solid var(--color-primary); + border-radius: 100%; + background-color: var(--color-white); + } + + .radio--input:checked + .radio--label::before { + border-color: var(--color-primary); + } + + .radio--input:focus + .radio--label::before, + .radio--input:hover + .radio--label::before { + border-color: var(--color-secondary); + } + + .radio--input:checked + .radio--label > .radio--icon { + display: inline-flex; + } +` diff --git a/plop-templates/radio-group/component.test.ts b/plop-templates/radio-group/component.test.ts new file mode 100644 index 0000000..e69de29 diff --git a/plop-templates/radio-group/component.ts b/plop-templates/radio-group/component.ts new file mode 100644 index 0000000..aea82c8 --- /dev/null +++ b/plop-templates/radio-group/component.ts @@ -0,0 +1,83 @@ +import { css } from "lit"; +import { html, LitElement } from "lit"; +import { customElement, query, property } from "lit/decorators.js"; +import { classMap } from "lit/directives/class-map.js"; +import "../material-icon/component"; +import { radioGroupStyles } from "./component.styles"; + +type RadioGroupOptions = { + [key: string]: string; +}; + +@customElement("{{meta.prefix}}-radio-group") +export class {{titleCase meta.prefix}}RadioGroup extends LitElement { + @query("input") + protected _radioGroupNode!: HTMLInputElement; + + static styles = [ + css` + *, + *::before, + *::after { + box-sizing: border-box; + } + + .sr-only { + clip: rect(0, 0, 0, 0); + overflow: hidden; + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + border-width: 0; + padding: 0; + white-space: nowrap; + } + `, + radioGroupStyles, + ]; + + {{> properties}} + + render() { + const { + disabled, + hiddenLabel, + label, + options, + name, + value, + _handleChange: handleChange, + } = this; + + const labelClasses = classMap({ + [`radio--label`]: true, + [`sr-only`]: hiddenLabel, + }); + + return html` +
+
${label}
+ ${Object.entries(options).map(([optionsKey, optionsValue], index) => + html` +
+ + +
+ ` + )} +
+ `; + } +}