Skip to content

Commit

Permalink
Merge pull request #59 from chasefleming/chasefleming/57
Browse files Browse the repository at this point in the history
Implement Remaining Semantic Elements
  • Loading branch information
chasefleming authored Nov 3, 2023
2 parents b88730b + b39e8dd commit 434191f
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 53 deletions.
66 changes: 14 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,58 +98,20 @@ In this example, if `isAdmin` is `true`, the `Admin Panel` link is rendered. Oth

### Supported Elements

`elem` provides utility functions for creating common HTML elements:

- `A`: Anchor `<a>`
- `Article`: Article `<article>`
- `Aside`: Aside `<aside>`
- `Blockquote`: Blockquote `<blockquote>`
- `Body`: Body `<body>`
- `Br`: Break `<br>`
- `Button`: Button `<button>`
- `Code`: Code `<code>`
- `Div`: Division `<div>`
- `Dl`: Description List `<dl>`
- `Dt`: Description Term `<dt>`
- `Dd`: Description Description `<dd>`
- `Em`: Emphasis `<em>`
- `Footer`: Footer `<footer>`
- `Form`: Form `<form>`
- `H1`: Heading 1 `<h1>`
- `H2`: Heading 2 `<h2>`
- `H3`: Heading 3 `<h3>`
- `Head`: Head `<head>`
- `Header`: Header `<header>`
- `Html`: HTML `<html>`
- `Hr`: Horizontal Rule `<hr>`
- `I`: Idiomatic Text `<i>`
- `Img`: Image `<img>`
- `Input`: Input `<input>`
- `Label`: Label `<label>`
- `Li`: List Item `<li>`
- `Link`: Link `<link>`
- `Main`: Main `<main>`
- `Meta`: Meta `<meta>`
- `Nav`: Navigation `<nav>`
- `Ol`: Ordered List `<ol>`
- `Option`: Dropdown option `<option>`
- `P`: Paragraph `<p>`
- `Pre`: Preformatted Text `<pre>`
- `Script`: Script `<script>`
- `Section`: Section `<section>`
- `Select`: Dropdown select `<select>`
- `Span`: Span `<span>`
- `Strong`: Strong `<strong>`
- `Table`: Table `<table>`
- `TBody`: Table Body `<tbody>`
- `Td`: Table Cell `<td>`
- `Textarea`: Textarea `<textarea>`
- `TFoot`: Table Footer `<tfoot>`
- `Th`: Table Header Cell `<th>`
- `THead`: Table Header `<thead>`
- `Title`: Title `<title>`
- `Tr`: Table Row `<tr>`
- `Ul`: Unordered List `<ul>`
`elem` provides utility functions for creating HTML elements:

### Supported Elements

- **Document Structure**: `Html`, `Head`, `Body`, `Title`, `Link`, `Meta`
- **Text Content**: `H1`, `H2`, `H3`, `P`, `Blockquote`, `Pre`, `Code`, `Em`, `Strong`, `I`, `Br`, `Hr`
- **Sectioning & Semantic Layout**: `Article`, `Aside`, `Footer`, `Header`, `Main`, `Nav`, `Section`
- **Form Elements**: `Form`, `Input`, `Textarea`, `Button`, `Select`, `Option`, `Label`, `Fieldset`, `Legend`, `Datalist`, `Meter`, `Output`, `Progress`
- **Interactive Elements**: `Dialog`, `Menu`
- **Grouping Content**: `Div`, `Span`, `Li`, `Ul`, `Ol`, `Dl`, `Dt`, `Dd`
- **Tables**: `Table`, `Tr`, `Td`, `Th`, `TBody`, `THead`, `TFoot`
- **Embedded Content**: `Img`
- **Script-supporting Elements**: `Script`, `Noscript`
- **Inline Semantic**: `A`, `Strong`, `Em`, `Code`, `I`

### Setting Styles with the `styles` Subpackage

Expand Down
7 changes: 6 additions & 1 deletion attrs/attrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,19 @@ const (
Cols = "cols"
Checked = "checked"
Disabled = "disabled"
For = "for" // Used with label elements
For = "for"
Form = "form"
List = "list"
Low = "low"
High = "high"
Max = "max"
MaxLength = "maxlength"
Method = "method" // e.g., "GET", "POST"
Min = "min"
Multiple = "multiple"
Name = "name"
NoValidate = "novalidate"
Optimum = "optimum"
Placeholder = "placeholder"
Readonly = "readonly"
Required = "required"
Expand Down
42 changes: 42 additions & 0 deletions elements.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,48 @@ func Section(props Attrs, children ...Node) *Element {
return NewElement("section", props, children...)
}

// ========== Semantic Form Elements ==========

func Fieldset(props Attrs, children ...Node) *Element {
return NewElement("fieldset", props, children...)
}

func Legend(props Attrs, children ...Node) *Element {
return NewElement("legend", props, children...)
}

func Datalist(props Attrs, children ...Node) *Element {
return NewElement("datalist", props, children...)
}

func Meter(props Attrs, children ...Node) *Element {
return NewElement("meter", props, children...)
}

func Output(props Attrs, children ...Node) *Element {
return NewElement("output", props, children...)
}

func Progress(props Attrs, children ...Node) *Element {
return NewElement("progress", props, children...)
}

// --- Semantic Interactive Elements ---

func Dialog(props Attrs, children ...Node) *Element {
return NewElement("dialog", props, children...)
}

func Menu(props Attrs, children ...Node) *Element {
return NewElement("menu", props, children...)
}

// --- Semantic Script Supporting Elements ---

func NoScript(props Attrs, children ...Node) *Element {
return NewElement("noscript", props, children...)
}

// --- Semantic Text Content Elements ---

func Address(props Attrs, children ...Node) *Element {
Expand Down
60 changes: 60 additions & 0 deletions elements_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,66 @@ func TestSection(t *testing.T) {
assert.Equal(t, expected, el.Render())
}

// --- Semantic Form Elements ---

func TestFieldset(t *testing.T) {
expected := `<fieldset class="custom-fieldset"><legend>Personal Information</legend><input name="name" type="text"></fieldset>`
el := Fieldset(Attrs{attrs.Class: "custom-fieldset"}, Legend(nil, Text("Personal Information")), Input(Attrs{attrs.Type: "text", attrs.Name: "name"}))
assert.Equal(t, expected, el.Render())
}

func TestLegend(t *testing.T) {
expected := `<legend class="custom-legend">Legend Title</legend>`
el := Legend(Attrs{attrs.Class: "custom-legend"}, Text("Legend Title"))
assert.Equal(t, expected, el.Render())
}

func TestDatalist(t *testing.T) {
expected := `<datalist id="exampleList"><option value="Option1">Option 1</option><option value="Option2">Option 2</option></datalist>`
el := Datalist(Attrs{attrs.ID: "exampleList"}, Option(Attrs{attrs.Value: "Option1"}, Text("Option 1")), Option(Attrs{attrs.Value: "Option2"}, Text("Option 2")))
assert.Equal(t, expected, el.Render())
}

func TestMeter(t *testing.T) {
expected := `<meter max="100" min="0" value="50">50%</meter>`
el := Meter(Attrs{attrs.Min: "0", attrs.Max: "100", attrs.Value: "50"}, Text("50%"))
assert.Equal(t, expected, el.Render())
}

func TestOutput(t *testing.T) {
expected := `<output for="inputId" name="result">Output</output>`
el := Output(Attrs{attrs.For: "inputId", attrs.Name: "result"}, Text("Output"))
assert.Equal(t, expected, el.Render())
}

func TestProgress(t *testing.T) {
expected := `<progress max="100" value="60"></progress>`
el := Progress(Attrs{attrs.Max: "100", attrs.Value: "60"})
assert.Equal(t, expected, el.Render())
}

// --- Semantic Interactive Elements ---

func TestDialog(t *testing.T) {
expected := `<dialog open><p>This is an open dialog window</p></dialog>`
el := Dialog(Attrs{attrs.Open: "true"}, P(nil, Text("This is an open dialog window")))
assert.Equal(t, expected, el.Render())
}

func TestMenu(t *testing.T) {
expected := `<menu><li>Item One</li><li>Item Two</li></menu>`
el := Menu(nil, Li(nil, Text("Item One")), Li(nil, Text("Item Two")))
assert.Equal(t, expected, el.Render())
}

// --- Semantic Script Supporting Elements ---

func TestNoScript(t *testing.T) {
expected := `<noscript><p>JavaScript is required for this application.</p></noscript>`
el := NoScript(nil, P(nil, Text("JavaScript is required for this application.")))
assert.Equal(t, expected, el.Render())
}

// --- Semantic Text Content Elements ---

func TestAddress(t *testing.T) {
Expand Down

0 comments on commit 434191f

Please sign in to comment.