Module:UtilsLayout/Tabs: Difference between revisions

From Zelda Wiki, the Zelda encyclopedia
Jump to navigation Jump to search
mNo edit summary
(Add ARIA roles so that tabs can at least be manipulated via keyboard when using screen readers. MediaWiki limitations prevent me from adding proper accessibility features, unfortunately.)
 
(17 intermediate revisions by 3 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local h = {}
local h = {}
local CLASS_TOOLTIP = require("Module:Constants/class/tooltip")


function p.tabs(data, options)
function p.tabs(data, options)
local options = options or {}
local options = options or {}
local format = options.format or "top"
local tabOptions = options.tabOptions or {}
local labelOptions = options.labelOptions or {}
local contentOptions = options.contentOptions or {}
local defaultTab = options.default or 1
local align = options.align or "left"
local align = options.align or "left"
local columns = options.columns
local collapse = options.collapse
local defaultTab = options.default or 1
local stretch = options.stretch
local fixedContentWidth = options.fixedContentWidth
local fixedContentHeight = options.fixedContentHeight
if #data == 1 and collapse then
if #data == 1 and tabOptions.collapse then
return data[1].content
return data[1].content
end
end
local tabContainer = h.tabContainer(data, defaultTab, format, align, columns, stretch)
local tabContainer = h.tabContainer(data, defaultTab, align, tabOptions, labelOptions)
local tabContents = h.tabContents(data, defaultTab, align, fixedContentWidth, fixedContentHeight)
local tabContents = h.tabContents(data, defaultTab, align, contentOptions)
local html = mw.html.create("div")
local html = mw.html.create("div")
:addClass("zw-tabs")
if format == "top" then
:addClass(tabOptions.stretch and "zw-tabs--stretch" or nil)
:addClass(tabOptions.columns and "zw-tabs--columns" or nil)
if tabOptions.position == "bottom" then
html:node(tabContents)
:node(tabContainer)
else
html:node(tabContainer)
html:node(tabContainer)
:node(tabContents)
:node(tabContents)
else
html:node(tabContents)
:node(tabContainer)
end
end
return tostring(html)
return tostring(html)
end
end


function h.tabContainer(data, defaultTab, format, align, columns, stretch)
function h.tabContainer(data, defaultTab, align, tabOptions, labelOptions)
local tabContainer = mw.html.create("div"):addClass("tabcontainer tabcontainer-" .. format)
local position = tabOptions.position or "top"
local stretch = tabOptions.stretch
if align then
local columns = tabOptions.columns
tabContainer:addClass("tabcontainer--"..align)
local labelAlignVertical = labelOptions.alignVertical or "center"
end
if stretch then
local tabContainer = mw.html.create("div")
tabContainer:addClass("tabcontainer--stretch")
:addClass("tabcontainer tabcontainer-"..position)
end
:addClass("tabcontainer--align-x-"..align)
if columns then
:attr("role", "tablist")
tabContainer:addClass("tabcontainer--columns")
end
for i, tabData in ipairs(data) do
for i, tabData in ipairs(data) do
local tab = mw.html.create("span")
local tab = mw.html.create("span")
:addClass("tab explain")
:addClass("tab")
:addClass(CLASS_TOOLTIP)
:addClass("tab--label-align-y-"..labelAlignVertical)
:attr("title", tabData.tooltip)
:attr("title", tabData.tooltip)
:attr("role", "tab")
:attr("tabindex", "0")
:wikitext(tabData.label)
:wikitext(tabData.label)
if i == defaultTab then
if i == defaultTab then
Line 54: Line 59:
if columns then
if columns then
tab:css({
tab:css({
["max-width"] = "calc(100%/"..columns.." - 3*"..columns.."px)"
["max-width"] = "calc(100%/"..columns.." - 2*"..(columns-1).."px)" -- the subtraction is to account for tab margins
})
})
end
end
Line 62: Line 67:
end
end


function h.tabContents(data, defaultTab, align, fixedContentWidth, fixedContentHeight)
function h.tabContents(data, defaultTab, align, contentOptions)
local alignVertical = contentOptions.alignVertical or "top"
local fixedWidth = contentOptions.fixedWidth
local fixedHeight = contentOptions.fixedHeight
local tabContents = mw.html.create("div")
local tabContents = mw.html.create("div")
:addClass("tabcontents")
:addClass("tabcontents")
:addClass("tabcontents--align-x-"..align)
if align then
:addClass("tabcontents--align-y-"..alignVertical)
tabContents:css("text-align", align)
 
end
if fixedWidth then
if fixedContentWidth then
tabContents:addClass("tabcontents--fixed-width")
tabContents:addClass("tabcontents--fixed-width")
if type(fixedWidth) == "number" then
tabContents:css("width", fixedWidth .. "px")
end
end
end
if fixedContentHeight then
if fixedHeight then
tabContents:addClass("tabcontents--fixed-height")
tabContents:addClass("tabcontents--fixed-height")
if type(fixedHeight) == "number" then
tabContents:css("height", fixedHeight .. "px")
end
end
end
Line 79: Line 93:
local content = mw.html.create("div")
local content = mw.html.create("div")
:addClass("content")
:addClass("content")
:wikitext(tabData.content)
:attr("role", "tabpanel")
:wikitext("\n", tabData.content)
if i == defaultTab then
if i == defaultTab then
content:addClass("content--active")
content:addClass("content--active")
Line 88: Line 103:
end
end


p.Schemas = {
function p.Schemas()
tabs = {
return {
data = {
tabs = {
type = "array",
data = {
required = true,
type = "array",
items = {
required = true,
items = {
type = "record",
properties = {
{
name = "label",
type = "string",
required = true,
desc = "Button text for the tab."
},
{
name = "tooltip",
type = "string",
desc = "Tooltip for the tab button",
},
{
name = "content",
type = "string",
required = true,
desc = "Content for the tab.",
},
}
}
},
options = {
type = "record",
type = "record",
properties = {
properties = {
{
{
name = "label",
name = "default",
type = "number",
default = 1,
desc = "Index of default tab.",
},
{
name = "align",
type = "string",
type = "string",
required = true,
enum = {"left", "center", "right"},
desc = "Button text for the tab."
default = mw.dumpObject("left"),
desc = "Horizontal alignment for tabs and their content.",
},
{
name = "tabOptions",
type = "record",
desc = "Display options for the tabs themselves.",
properties = {
{
name = "position",
type = "string",
enum = {"top", "bottom"},
default = mw.dumpObject("top"),
desc = "If <code>top</code> (default), the tabs are placed above their content. If <code>bottom</code>, then the opposite."
},
{
name = "collapse",
type = "boolean",
desc = "If truthy, tabs will not be rendered if there is only one tab. The content of that tab will simply be rendered instead."
},
{
name = "stretch",
type = "boolean",
desc = "If true, then tabs will stretch to fill the available space in their container.",
},
{
name = "columns",
type = "number",
desc = "If specified, the tabs will attempt to arrange themselves in N columns of equal width. This option is not compatible with <code>stretch</code>."
},
},
},
},
{
{
name = "tooltip",
name = "labelOptions",
type = "string",
type = "record",
desc = "Tooltip for the tab button",
desc = "Display options for the tab labels.",
properties = {
{
name = "alignVertical",
type = "string",
enum = {"center", "bottom"},
default = mw.dumpObject("center"),
desc = "Vertical alignment of the label with respect to its tab. Options are: <code>center</code> (default) and <code>bottom</code>.",
},
},
},
},
{
{
name = "content",
name = "contentOptions",
type = "string",
type = "record",
required = true,
desc = "Display options for the tab contents.",
desc = "Content for the tab.",
properties = {
{
name = "fixedWidth",
oneOf = {
{ type = "boolean" },
{ type = "number" },
},
desc = "Width for the tab container in <code>px</code>. Or, if set to <code>true</code>, the tab container will  assume the width of the largest tab. By default, the tab container assumes the width of the current tab."
},
{
name = "fixedHeight",
oneOf = {
{ type = "boolean" },
{ type = "number" },
},
desc = "Height for the tab container in <code>px</code>. Or, if set to <code>true</code>, the tab container will  assume the height of the largest tab. By default, the tab container assumes the height of the current tab.",
},
{
name = "alignVertical",
type = "string",
enum = {"top", "center", "bottom"},
default = mw.dumpObject("top"),
desc = "Vertical alignment of tab contents with respect to the tab container. Useful only alonside <code>fixedHeight</code>."
},
},
},
},
}
},
}
},
},
}
options = {
}
type = "record",
end
properties = {
 
function p.Documentation()
return {
tabs = {
params = {"data", "options"},
returns = "HTML markup rendering tabs.",
cases = {
resultOnly = true,
{
{
name = "default",
args = {
type = "number",
{
default = 1,
{
desc = "Index of default tab.",
label = "Tab1",
content = "Content1",
},
{
label = "Tab2",
content = "Content2"
},
},
}
},
},
{
{
name = "collapse",
args = {
type = "boolean",
{
desc = "If truthy, tabs will not be rendered if there is only one tab. The content of that tab will simply be rendered instead."
{
label = "Tab1",
content = "Content1",
},
{
label = "Tab2",
content = "Content2"
},
},
{
tabOptions = {
stretch = true,
}
},
},
},
},
{
{
name = "format",
args = {
type = "string",
{
enum = {"top", "bottom"},
{
default = mw.dumpObject("top"),
label = "Tab1",
desc = "If <code>top</code>, the tabs are placed above their content. If <code>bottom</code>, then the opposite."
tooltip = "This is the first tab.",
content = "Content1"
},
{
label = "Tab2",
tooltip = "This is the second tab.",
content = "Content2"
},
{
label = "Tab3",
tooltip = "This is the third tab.",
content = "Content3"
}
},
{
default = 2,
align = "center",
tabOptions = {
position = "bottom",
},
}
}
},
},
{
{
name = "align",
desc = "Tabs display even for a single tab unless <code>collapse</code> is set to true.",
type = "string",
args = {
enum = {"left", "center", "right"},
{{ label = "Single Tab", content = "Content" }}
default = mw.dumpObject("left"),
}
desc = "Horizontal alignment for tabs and their content.",
},
},
{
{
name = "stretch",
args = {
type = "boolean",
{{ label = "Single Tab", content = "Content" }},
desc = "If true, then tabs will stretch to fill the available space in their container.",
{
tabOptions = {
collapse = true
}
},
}
},
},
{
{
name = "columns",
desc = "<code>fixedtWidth</code> and <code>fixedHeight</code> determine how the overall tab container is sized.",
type = "number",
args = {
desc = "If specified, the tabs will attempt to arrange themselves in N columns of equal width. This option is not compatible with <code>stretch</code>."
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
},
},
},
{
{
name = "fixedContentWidth",
args = {
type = "boolean",
{
desc = "If truthy, the tab container will always assume the width of the largest tab (as opposed to the width of the current tab)."
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
{
contentOptions = {
fixedWidth = true,
},
},
},
},
},
{
{
name = "fixedContentHeight",
args = {
type = "boolean",
desc = "If truthy, the tab container will always assume the height of the tallest tab (as opposed to that of the current tab).",
}
}
},
}
}
 
p.Documentation = {
tabs = {
params = {"data", "options"},
returns = "HTML markup rendering tabs.",
cases = {
resultOnly = true,
{
args = {
{
{
{
label = "Tab1",
{ label = "Small Tab", content = "meep" },
content = "Content1",
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
},
{
{
label = "Tab2",
contentOptions = {
content = "Content2"
fixedHeight = true,
},
},
},
},
},
}
},
},
{
{
args = {
args = {
{
{
{
label = "Tab1",
{ label = "Small Tab", content = "meep" },
content = "Content1",
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
{
contentOptions = {
fixedWidth = true,
fixedHeight = true,
alignVertical = "center",
},
},
},
},
},
{
args = {
{
{
label = "Tab2",
{ label = "Small Tab", content = "meep" },
content = "Content2"
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
},
},
{
{
contentOptions = {
stretch = true,
fixedWidth = 80,
},
fixedHeight = 80,
alignVertical = "center",
},
},
},
},
},
},
{
{
desc = "When images are used as tab labels, the label alignment options can be useful.",
args = {
args = {
{
{
{
label = "Tab1",
{ label = "[[File:ST Engine Icon.png|link=]]", content = "Engines" },
tooltip = "This is the first tab.",
{ label = "[[File:ST Passenger Car Icon.png|link=]]", content = "Passenger Cars" },
content = "Content1"
},
},
{
{
label = "Tab2",
labelOptions = {
tooltip = "This is the second tab.",
alignVertical = "bottom",
content = "Content2"
},
},
},
{
label = "Tab3",
tooltip = "This is the third tab.",
content = "Content3"
}
},
{
format = "bottom",
align = "center",
default = 2,
}
}
},
{
desc = "Tabs display even for a single tab unless <code>collapse</code> is set to true.",
args = {
{{ label = "Single Tab", content = "Content" }}
}
},
{
args = {
{{ label = "Single Tab", content = "Content" }},
{ collapse = true }
}
},
{
desc = "<code>fixedContentWidth</code> and <code>fixedContentHeight</code> determine how the overall tab container is sized.",
args = {
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
},
},
},
},
{
args = {
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
{ fixedContentWidth = true },
},
},
{
args = {
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
{ fixedContentHeight = true },
},
},
{
args = {
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
{
fixedContentWidth = true,
fixedContentHeight = true,
},
},
},
},
},
},
},
}
}
end


return p
return p

Latest revision as of 23:37, 25 November 2023

This module exports the following functions.

tabs

tabs(data, [options])

Parameters

  • data
    label
    Button text for the tab.
    [tooltip]
    Tooltip for the tab button
    content
    Content for the tab.
  • [options]
    [default=1]
    Index of default tab.
    [align="left"]
    Horizontal alignment for tabs and their content.
    [tabOptions]
    Display options for the tabs themselves.
    [position="top"]
    If top (default), the tabs are placed above their content. If bottom, then the opposite.
    [collapse]
    If truthy, tabs will not be rendered if there is only one tab. The content of that tab will simply be rendered instead.
    [stretch]
    If true, then tabs will stretch to fill the available space in their container.
    [columns]
    If specified, the tabs will attempt to arrange themselves in N columns of equal width. This option is not compatible with stretch.
    [labelOptions]
    Display options for the tab labels.
    [alignVertical="center"]
    Vertical alignment of the label with respect to its tab. Options are: center (default) and bottom.
    [contentOptions]
    Display options for the tab contents.
    [fixedWidth]
    Width for the tab container in px. Or, if set to true, the tab container will assume the width of the largest tab. By default, the tab container assumes the width of the current tab.
    [fixedHeight]
    Height for the tab container in px. Or, if set to true, the tab container will assume the height of the largest tab. By default, the tab container assumes the height of the current tab.
    [alignVertical="top"]
    Vertical alignment of tab contents with respect to the tab container. Useful only alonside fixedHeight.

Returns

  • HTML markup rendering tabs.

Examples

#InputResult
1
tabs({
  {
    content = "Content1",
    label = "Tab1",
  },
  {
    content = "Content2",
    label = "Tab2",
  },
})
Tab1Tab2
Content1
Content2
2
tabs(
  {
    {
      content = "Content1",
      label = "Tab1",
    },
    {
      content = "Content2",
      label = "Tab2",
    },
  },
  {
    tabOptions = { stretch = true },
  }
)
Tab1Tab2
Content1
Content2
3
tabs(
  {
    {
      tooltip = "This is the first tab.",
      content = "Content1",
      label = "Tab1",
    },
    {
      tooltip = "This is the second tab.",
      content = "Content2",
      label = "Tab2",
    },
    {
      tooltip = "This is the third tab.",
      content = "Content3",
      label = "Tab3",
    },
  },
  {
    align = "center",
    default = 2,
    tabOptions = { position = "bottom" },
  }
)
Content1
Content2
Content3
Tab1Tab2Tab3
Tabs display even for a single tab unless collapse is set to true.
4
tabs({
  {
    content = "Content",
    label = "Single Tab",
  },
})
Single Tab
Content
5
tabs(
  {
    {
      content = "Content",
      label = "Single Tab",
    },
  },
  {
    tabOptions = { collapse = true },
  }
)
Content
fixedtWidth and fixedHeight determine how the overall tab container is sized.
6
tabs({
  {
    content = "meep",
    label = "Small Tab",
  },
  {
    content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep",
    label = "Wide Tab",
  },
  {
    content = "m\ne\ne\ne\ne\np",
    label = "Tall tab",
  },
})
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep

m e e e e

p
7
tabs(
  {
    {
      content = "meep",
      label = "Small Tab",
    },
    {
      content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep",
      label = "Wide Tab",
    },
    {
      content = "m\ne\ne\ne\ne\np",
      label = "Tall tab",
    },
  },
  {
    contentOptions = { fixedWidth = true },
  }
)
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeep

m e e e e

p
8
tabs(
  {
    {
      content = "meep",
      label = "Small Tab",
    },
    {
      content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep",
      label = "Wide Tab",
    },
    {
      content = "m\ne\ne\ne\ne\np",
      label = "Tall tab",
    },
  },
  {
    contentOptions = { fixedHeight = true },
  }
)
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep

m e e e e

p
9
tabs(
  {
    {
      content = "meep",
      label = "Small Tab",
    },
    {
      content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep",
      label = "Wide Tab",
    },
    {
      content = "m\ne\ne\ne\ne\np",
      label = "Tall tab",
    },
  },
  {
    contentOptions = {
      fixedWidth = true,
      alignVertical = "center",
      fixedHeight = true,
    },
  }
)
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeep

m e e e e

p
10
tabs(
  {
    {
      content = "meep",
      label = "Small Tab",
    },
    {
      content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep",
      label = "Wide Tab",
    },
    {
      content = "m\ne\ne\ne\ne\np",
      label = "Tall tab",
    },
  },
  {
    contentOptions = {
      fixedWidth = 80,
      alignVertical = "center",
      fixedHeight = 80,
    },
  }
)
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeep

m e e e e

p
When images are used as tab labels, the label alignment options can be useful.
11
tabs(
  {
    {
      content = "Engines",
      label = "[[File:ST Engine Icon.png|link=]]",
    },
    {
      content = "Passenger Cars",
      label = "[[File:ST Passenger Car Icon.png|link=]]",
    },
  },
  {
    labelOptions = { alignVertical = "bottom" },
  }
)
Engines
Passenger Cars

local p = {}
local h = {}

local CLASS_TOOLTIP = require("Module:Constants/class/tooltip")

function p.tabs(data, options)
	local options = options or {}
	local tabOptions = options.tabOptions or {}
	local labelOptions = options.labelOptions or {}
	local contentOptions = options.contentOptions or {}
	
	local defaultTab = options.default or 1
	local align = options.align or "left"
	
	if #data == 1 and tabOptions.collapse then
		return data[1].content
	end
	
	local tabContainer = h.tabContainer(data, defaultTab, align, tabOptions, labelOptions)
	local tabContents = h.tabContents(data, defaultTab, align, contentOptions)
	
	local html = mw.html.create("div")
		:addClass("zw-tabs")
		:addClass(tabOptions.stretch and "zw-tabs--stretch" or nil)
		:addClass(tabOptions.columns and "zw-tabs--columns" or nil)
	if tabOptions.position == "bottom" then
		html:node(tabContents)
			:node(tabContainer)
	else
		html:node(tabContainer)
			:node(tabContents)
	end
	return tostring(html)
end

function h.tabContainer(data, defaultTab, align, tabOptions, labelOptions)
	local position = tabOptions.position or "top"
	local stretch = tabOptions.stretch
	local columns = tabOptions.columns
	local labelAlignVertical = labelOptions.alignVertical or "center"
	
	local tabContainer = mw.html.create("div")
		:addClass("tabcontainer tabcontainer-"..position)
		:addClass("tabcontainer--align-x-"..align)
		:attr("role", "tablist")
	
	for i, tabData in ipairs(data) do
		local tab = mw.html.create("span")
			:addClass("tab")
			:addClass(CLASS_TOOLTIP)
			:addClass("tab--label-align-y-"..labelAlignVertical)
			:attr("title", tabData.tooltip)
			:attr("role", "tab")
			:attr("tabindex", "0")
			:wikitext(tabData.label)
		if i == defaultTab then
			tab:addClass("active")
		end
		if columns then
			tab:css({
				["max-width"] = "calc(100%/"..columns.." - 2*"..(columns-1).."px)" -- the subtraction is to account for tab margins
			})
		end
		tabContainer:node(tab)
	end
	return tabContainer
end

function h.tabContents(data, defaultTab, align, contentOptions)
	local alignVertical = contentOptions.alignVertical or "top"
	local fixedWidth = contentOptions.fixedWidth
	local fixedHeight = contentOptions.fixedHeight
	
	local tabContents = mw.html.create("div")
		:addClass("tabcontents")
		:addClass("tabcontents--align-x-"..align)
		:addClass("tabcontents--align-y-"..alignVertical)

	if fixedWidth then
		tabContents:addClass("tabcontents--fixed-width")
		if type(fixedWidth) == "number" then
			tabContents:css("width", fixedWidth .. "px")
		end
	end
	if fixedHeight then
		tabContents:addClass("tabcontents--fixed-height")
		if type(fixedHeight) == "number" then
			tabContents:css("height", fixedHeight .. "px")
		end
	end
		
	for i, tabData in ipairs(data) do
		local content = mw.html.create("div")
			:addClass("content")
			:attr("role", "tabpanel")
			:wikitext("\n", tabData.content)
		if i == defaultTab then
			content:addClass("content--active")
		end
		tabContents:node(content)
	end
	return tabContents
end

function p.Schemas()
	return {
		tabs = {
			data = {
				type = "array",
				required = true,
				items = {
					type = "record",
					properties = {
						{
							name = "label",
							type = "string",
							required = true,
							desc = "Button text for the tab."
						},
						{
							name = "tooltip",
							type = "string",
							desc = "Tooltip for the tab button",
						},
						{
							name = "content",
							type = "string", 
							required = true,
							desc = "Content for the tab.",
						},
					}
				}
			},
			options = {
				type = "record",
				properties = {
					{
						name = "default",
						type = "number",
						default = 1,
						desc = "Index of default tab.",
					},
					{
						name = "align",
						type = "string",
						enum = {"left", "center", "right"},
						default = mw.dumpObject("left"),
						desc = "Horizontal alignment for tabs and their content.",
					},
					{
						name = "tabOptions",
						type = "record",
						desc = "Display options for the tabs themselves.",
						properties = {
							{
								name = "position",
								type = "string",
								enum = {"top", "bottom"},
								default = mw.dumpObject("top"),
								desc = "If <code>top</code> (default), the tabs are placed above their content. If <code>bottom</code>, then the opposite."
							},
							{
								name = "collapse",
								type = "boolean",
								desc = "If truthy, tabs will not be rendered if there is only one tab. The content of that tab will simply be rendered instead."
							},
							{
								name = "stretch",
								type = "boolean",
								desc = "If true, then tabs will stretch to fill the available space in their container.",
							},
							{
								name = "columns",
								type = "number",
								desc = "If specified, the tabs will attempt to arrange themselves in N columns of equal width. This option is not compatible with <code>stretch</code>."
							},
						},
					},
					{
						name = "labelOptions",
						type = "record",
						desc = "Display options for the tab labels.",
						properties = {
							{
								name = "alignVertical",
								type = "string",
								enum = {"center", "bottom"},
								default = mw.dumpObject("center"),
								desc = "Vertical alignment of the label with respect to its tab. Options are: <code>center</code> (default) and <code>bottom</code>.",
							},
						},
					},
					{
						name = "contentOptions",
						type = "record",
						desc = "Display options for the tab contents.",
						properties = {
							{
								name = "fixedWidth",
								oneOf = {
									{ type = "boolean" },
									{ type = "number" },
								},
								desc = "Width for the tab container in <code>px</code>. Or, if set to <code>true</code>, the tab container will  assume the width of the largest tab. By default, the tab container assumes the width of the current tab."
							},
							{
								name = "fixedHeight",
								oneOf = {
									{ type = "boolean" },
									{ type = "number" },
								},
								desc = "Height for the tab container in <code>px</code>. Or, if set to <code>true</code>, the tab container will  assume the height of the largest tab. By default, the tab container assumes the height of the current tab.",
							},
							{
								name = "alignVertical",
								type = "string",
								enum = {"top", "center", "bottom"},
								default = mw.dumpObject("top"),
								desc = "Vertical alignment of tab contents with respect to the tab container. Useful only alonside <code>fixedHeight</code>."
							},
						},
					},
				},
			},
		}
	}
end

function p.Documentation() 
	return {
		tabs = {
			params = {"data", "options"},
			returns = "HTML markup rendering tabs.",
			cases = {
				resultOnly = true,
				{
					args = {
						{
							{
								label = "Tab1",
								content = "Content1",
							},
							{
								label = "Tab2",
								content = "Content2"
							},
						},
					}
				},
				{
					args = {
						{
							{
								label = "Tab1",
								content = "Content1",
							},
							{
								label = "Tab2",
								content = "Content2"
							},
						},
						{
							tabOptions = {
								stretch = true,
							}
						},
					},
				},
				{
					args = {
						{
							{
								label = "Tab1",
								tooltip = "This is the first tab.",
								content = "Content1"
							},
							{
								label = "Tab2",
								tooltip = "This is the second tab.",
								content = "Content2"
							},
							{
								label = "Tab3",
								tooltip = "This is the third tab.",
								content = "Content3"
							}
						},
						{
							default = 2,
							align = "center",
							tabOptions = {
								position = "bottom",
							},
						}
					}
				},
				{
					desc = "Tabs display even for a single tab unless <code>collapse</code> is set to true.",
					args = {
						{{ label = "Single Tab", content = "Content" }}
					}
				},
				{
					args = {
						{{ label = "Single Tab", content = "Content" }},
						{ 
							tabOptions = {
								collapse = true
							}
						},
					}
				},
				{
					desc = "<code>fixedtWidth</code> and <code>fixedHeight</code> determine how the overall tab container is sized.",
					args = {
						{
							{ label = "Small Tab", content = "meep" },
							{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep" },
							{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
						},
					},
				},
				{
					args = {
						{
							{ label = "Small Tab", content = "meep" },
							{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
							{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
						},
						{
							contentOptions = {
								fixedWidth = true,
							},
						},
	 				},
				},
				{
					args = {
						{
							{ label = "Small Tab", content = "meep" },
							{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep" },
							{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
						},
						{
							contentOptions = {
								fixedHeight = true,
							},
						},
	 				},
				},
				{
					args = {
						{
							{ label = "Small Tab", content = "meep" },
							{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
							{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
						},
						{ 
							contentOptions = {
								fixedWidth = true,
								fixedHeight = true,
								alignVertical = "center",
							},
						},
	 				},
				},
				{
					args = {
						{
							{ label = "Small Tab", content = "meep" },
							{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
							{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
						},
						{ 
							contentOptions = {
								fixedWidth = 80,
								fixedHeight = 80,
								alignVertical = "center",
							},
						},
	 				},
				},
				{
					desc = "When images are used as tab labels, the label alignment options can be useful.",
					args = {
						{
							{ label = "[[File:ST Engine Icon.png|link=]]", content = "Engines" },
							{ label = "[[File:ST Passenger Car Icon.png|link=]]", content = "Passenger Cars" },
						},
						{
							labelOptions = {
								alignVertical = "bottom",
							},
						},
					},
				},
			},
		},
	}
end

return p