summaryrefslogtreecommitdiffstats
path: root/toolkit/content/widgets/mach_commands.py
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/widgets/mach_commands.py')
-rw-r--r--toolkit/content/widgets/mach_commands.py164
1 files changed, 164 insertions, 0 deletions
diff --git a/toolkit/content/widgets/mach_commands.py b/toolkit/content/widgets/mach_commands.py
new file mode 100644
index 0000000000..2bc6044e24
--- /dev/null
+++ b/toolkit/content/widgets/mach_commands.py
@@ -0,0 +1,164 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import re
+
+from mach.decorators import Command, CommandArgument
+
+LICENSE_HEADER = """/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"""
+
+JS_HEADER = """{license}
+import {{ html }} from "../vendor/lit.all.mjs";
+import {{ MozLitElement }} from "../lit-utils.mjs";
+
+/**
+ * Component description goes here.
+ *
+ * @tagname {element_name}
+ * @property {{string}} variant - Property description goes here
+ */
+export default class {class_name} extends MozLitElement {{
+ static properties = {{
+ variant: {{ type: String }},
+ }};
+
+ // Use a relative URL in storybook to get faster reloads on style changes.
+ static stylesheetUrl = window.IS_STORYBOOK
+ ? "./{element_name}/{element_name}.css"
+ : "chrome://global/content/elements/{element_name}.css";
+
+ constructor() {{
+ super();
+ this.variant = "default";
+ }}
+
+ render() {{
+ return html`
+ <link rel="stylesheet" href=${{this.constructor.stylesheetUrl}} />
+ <div>Variant type: ${{this.variant}}</div>
+ `;
+ }}
+}}
+customElements.define("{element_name}", {class_name});
+"""
+
+STORY_HEADER = """{license}
+import {{ html }} from "../vendor/lit.all.mjs";
+// eslint-disable-next-line import/no-unassigned-import
+import "./{element_name}.mjs";
+
+export default {{
+ title: "UI Widgets/{story_name}",
+ component: "{element_name}",
+ argTypes: {{
+ variant: {{
+ options: ["default", "other"],
+ control: {{ type: "select" }},
+ }},
+ }},
+}};
+
+const Template = ({{ variant }}) => html`
+ <{element_name} .variant=${{variant}}></{element_name}>
+`;
+
+export const Default = Template.bind({{}});
+Default.args = {{
+ variant: "default",
+}};
+"""
+
+
+def run_mach(command_context, cmd, **kwargs):
+ return command_context._mach_context.commands.dispatch(
+ cmd, command_context._mach_context, **kwargs
+ )
+
+
+def run_npm(command_context, args):
+ return run_mach(
+ command_context, "npm", args=[*args, "--prefix=browser/components/storybook"]
+ )
+
+
+@Command(
+ "addwidget",
+ category="misc",
+ description="Scaffold a front-end component.",
+)
+@CommandArgument(
+ "names",
+ nargs="+",
+ help="Component names to create in kebab-case, eg. my-card.",
+)
+def addwidget(command_context, names):
+ for name in names:
+ component_dir = "toolkit/content/widgets/{0}".format(name)
+
+ try:
+ os.mkdir(component_dir)
+ except FileExistsError:
+ pass
+
+ with open("{0}/{1}.mjs".format(component_dir, name), "w", newline="\n") as f:
+ class_name = "".join(p.capitalize() for p in name.split("-"))
+ f.write(
+ JS_HEADER.format(
+ license=LICENSE_HEADER,
+ element_name=name,
+ class_name=class_name,
+ )
+ )
+
+ with open("{0}/{1}.css".format(component_dir, name), "w", newline="\n") as f:
+ f.write(LICENSE_HEADER)
+
+ test_name = name.replace("-", "_")
+ test_path = "toolkit/content/tests/widgets/test_{0}.html".format(test_name)
+ jar_path = "toolkit/content/jar.mn"
+ jar_lines = None
+ with open(jar_path, "r") as f:
+ jar_lines = f.readlines()
+ elements_startswith = " content/global/elements/"
+ new_css_line = "{0}{1}.css (widgets/{1}/{1}.css)\n".format(
+ elements_startswith, name
+ )
+ new_js_line = "{0}{1}.mjs (widgets/{1}/{1}.mjs)\n".format(
+ elements_startswith, name
+ )
+ new_jar_lines = []
+ found_elements_section = False
+ added_widget = False
+ for line in jar_lines:
+ if line.startswith(elements_startswith):
+ found_elements_section = True
+ if found_elements_section and not added_widget and line > new_css_line:
+ added_widget = True
+ new_jar_lines.append(new_css_line)
+ new_jar_lines.append(new_js_line)
+ new_jar_lines.append(line)
+
+ with open(jar_path, "w", newline="\n") as f:
+ f.write("".join(new_jar_lines))
+
+ story_path = "{0}/{1}.stories.mjs".format(component_dir, name)
+ with open(story_path, "w", newline="\n") as f:
+ story_name = " ".join(
+ name for name in re.findall(r"[A-Z][a-z]+", class_name) if name != "Moz"
+ )
+ f.write(
+ STORY_HEADER.format(
+ license=LICENSE_HEADER,
+ element_name=name,
+ story_name=story_name,
+ )
+ )
+
+ run_mach(
+ command_context, "addtest", argv=[test_path, "--suite", "mochitest-chrome"]
+ )