lookbook 1.5.5 → 2.0.0.beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -31
  3. data/app/assets/lookbook/css/lookbook.css +9 -0
  4. data/app/assets/lookbook/css/themes/blue.css +7 -0
  5. data/app/assets/lookbook/css/themes/green.css +7 -0
  6. data/app/assets/lookbook/css/themes/indigo.css +7 -0
  7. data/app/assets/lookbook/css/themes/rose.css +7 -0
  8. data/app/assets/lookbook/css/themes/zinc.css +7 -0
  9. data/app/assets/lookbook/css/tooltip.css +9 -6
  10. data/app/assets/lookbook/img/lucide-sprite.svg +4960 -0
  11. data/app/assets/lookbook/js/app.js +22 -4
  12. data/app/assets/lookbook/js/helpers/dom.js +4 -7
  13. data/app/assets/lookbook/js/helpers/string.js +4 -11
  14. data/app/assets/lookbook/js/index.js +61 -0
  15. data/app/assets/lookbook/js/lib/lookbook.js +113 -0
  16. data/app/assets/lookbook/js/lib/tippy.js +1 -0
  17. data/app/assets/lookbook/js/lookbook-core.js +1 -0
  18. data/app/assets/lookbook/js/lookbook.js +2 -61
  19. data/app/components/lookbook/base_component.rb +3 -1
  20. data/app/components/lookbook/button/component.html.erb +13 -24
  21. data/app/components/lookbook/button/component.js +13 -3
  22. data/app/components/lookbook/button/component.rb +16 -25
  23. data/app/components/lookbook/code/component.rb +0 -2
  24. data/app/components/lookbook/copy_button/component.html.erb +5 -5
  25. data/app/components/lookbook/copy_button/component.rb +6 -3
  26. data/app/components/lookbook/debug_menu/component.html.erb +1 -0
  27. data/app/components/lookbook/debug_menu/component.rb +12 -1
  28. data/app/components/lookbook/display_options/editor/component.html.erb +1 -1
  29. data/app/components/lookbook/display_options/field/component.css +0 -26
  30. data/app/components/lookbook/display_options/field/component.html.erb +1 -1
  31. data/app/components/lookbook/embed/component.html.erb +6 -51
  32. data/app/components/lookbook/embed/component.rb +17 -16
  33. data/app/components/lookbook/embed/inspector/component.html.erb +102 -0
  34. data/app/components/lookbook/embed/inspector/component.js +46 -0
  35. data/app/components/lookbook/embed/inspector/component.rb +64 -0
  36. data/app/components/lookbook/embed_code_dropdown/component.css +12 -0
  37. data/app/components/lookbook/embed_code_dropdown/component.html.erb +19 -0
  38. data/app/components/lookbook/embed_code_dropdown/component.js +26 -0
  39. data/app/components/lookbook/embed_code_dropdown/component.rb +41 -0
  40. data/app/components/lookbook/header/component.html.erb +7 -6
  41. data/app/components/lookbook/header/component.rb +5 -1
  42. data/app/components/lookbook/icon/component.html.erb +1 -1
  43. data/app/components/lookbook/icon_button/component.html.erb +20 -0
  44. data/app/components/lookbook/icon_button/component.rb +46 -0
  45. data/app/components/lookbook/nav/component.html.erb +0 -1
  46. data/app/components/lookbook/nav/entity/component.rb +2 -2
  47. data/app/components/lookbook/nav/item/component.rb +1 -1
  48. data/app/components/lookbook/page_tabs/component.html.erb +2 -2
  49. data/app/components/lookbook/params/editor/component.rb +1 -0
  50. data/app/components/lookbook/prose/component.rb +1 -3
  51. data/app/components/lookbook/tabs/component.html.erb +2 -2
  52. data/app/components/lookbook/tabs/component.js +1 -1
  53. data/app/components/lookbook/tag_component.rb +2 -1
  54. data/app/components/lookbook/text_button/component.html.erb +26 -0
  55. data/app/components/lookbook/text_button/component.rb +42 -0
  56. data/app/components/lookbook/toolbar/component.html.erb +1 -1
  57. data/app/components/lookbook/viewport/component.rb +0 -4
  58. data/app/controllers/concerns/lookbook/targetable_concern.rb +26 -22
  59. data/app/controllers/concerns/lookbook/with_panels_concern.rb +30 -0
  60. data/app/controllers/concerns/lookbook/with_preview_controller_concern.rb +4 -3
  61. data/app/controllers/lookbook/application_controller.rb +9 -12
  62. data/app/controllers/lookbook/embeds_controller.rb +148 -0
  63. data/app/controllers/lookbook/inspector_controller.rb +3 -22
  64. data/app/controllers/lookbook/page_controller.rb +7 -6
  65. data/app/controllers/lookbook/pages_controller.rb +3 -4
  66. data/app/controllers/lookbook/preview_controller.rb +17 -0
  67. data/app/controllers/lookbook/previews_controller.rb +10 -30
  68. data/app/helpers/lookbook/application_helper.rb +3 -19
  69. data/app/views/layouts/lookbook/application.html.erb +85 -60
  70. data/app/views/layouts/lookbook/embed.html.erb +16 -0
  71. data/app/views/layouts/lookbook/shell.html.erb +1 -1
  72. data/app/views/layouts/lookbook/skeleton.html.erb +13 -8
  73. data/app/views/lookbook/404.html.erb +2 -2
  74. data/app/views/lookbook/embeds/show.html.erb +12 -0
  75. data/app/views/lookbook/inspector/panels/_notes.html.erb +1 -1
  76. data/app/views/lookbook/inspector/panels/_output.html.erb +3 -3
  77. data/app/views/lookbook/inspector/panels/_source.html.erb +6 -6
  78. data/app/views/lookbook/inspector/show.html.erb +130 -123
  79. data/app/views/lookbook/pages/show.html.erb +81 -34
  80. data/app/views/lookbook/partials/_iframe_content_scripts.html.erb +1 -0
  81. data/app/views/lookbook/partials/_user_styles.html.erb +5 -0
  82. data/app/views/lookbook/previews/group.html.erb +14 -0
  83. data/app/views/lookbook/previews/preview.html.erb +5 -0
  84. data/app/views/lookbook/previews/show.html.erb +1 -0
  85. data/config/app.yml +31 -16
  86. data/config/panels.yml +23 -25
  87. data/config/routes.rb +3 -1
  88. data/config/tags.yml +6 -2
  89. data/lib/lookbook/cable/cable.rb +53 -0
  90. data/lib/lookbook/engine.rb +105 -93
  91. data/lib/lookbook/entities/collections/entity_collection.rb +11 -6
  92. data/lib/lookbook/entities/collections/page_collection.rb +33 -8
  93. data/lib/lookbook/entities/collections/preview_collection.rb +42 -17
  94. data/lib/lookbook/entities/collections/render_target_collection.rb +4 -0
  95. data/lib/lookbook/entities/collections/scenario_collection.rb +4 -0
  96. data/lib/lookbook/entities/concerns/{annotatable.rb → annotatable_entity.rb} +7 -6
  97. data/lib/lookbook/entities/concerns/{inspectable.rb → inspectable_entity.rb} +2 -1
  98. data/lib/lookbook/entities/concerns/{locatable.rb → locatable_entity.rb} +8 -14
  99. data/lib/lookbook/entities/concerns/navigable_entity.rb +44 -0
  100. data/lib/lookbook/entities/entity.rb +7 -2
  101. data/lib/lookbook/entities/{page.rb → page_entity.rb} +10 -6
  102. data/lib/lookbook/entities/{page_section.rb → page_section_entity.rb} +1 -1
  103. data/lib/lookbook/entities/preview_entity.rb +99 -0
  104. data/lib/lookbook/entities/renderable_entity.rb +50 -0
  105. data/lib/lookbook/entities/rendered_scenario_entity.rb +53 -0
  106. data/lib/lookbook/entities/scenario_entity.rb +112 -0
  107. data/lib/lookbook/entities/scenario_group_entity.rb +53 -0
  108. data/lib/lookbook/error.rb +5 -5
  109. data/lib/lookbook/file_watcher.rb +19 -35
  110. data/lib/lookbook/helpers/class_names_helper.rb +28 -0
  111. data/lib/lookbook/helpers/page_helper.rb +18 -0
  112. data/{app/helpers/lookbook → lib/lookbook/helpers}/preview_helper.rb +3 -0
  113. data/lib/lookbook/helpers/ui_elements_helper.rb +115 -0
  114. data/lib/lookbook/preview.rb +79 -0
  115. data/lib/lookbook/preview_controller_actions.rb +50 -0
  116. data/lib/lookbook/preview_parser.rb +4 -2
  117. data/lib/lookbook/reloaders.rb +71 -0
  118. data/lib/lookbook/runtime_context.rb +49 -0
  119. data/lib/lookbook/services/data/resolvers/data_resolver.rb +4 -6
  120. data/lib/lookbook/services/entities/entity_tree_builder.rb +6 -6
  121. data/lib/lookbook/services/list_resolver.rb +35 -0
  122. data/lib/lookbook/services/markdown_renderer.rb +12 -2
  123. data/lib/lookbook/services/priority_prefix_parser.rb +16 -0
  124. data/lib/lookbook/services/urls/search_param_encoder.rb +16 -0
  125. data/lib/lookbook/services/urls/search_param_parser.rb +7 -6
  126. data/lib/lookbook/stores/config_store.rb +16 -16
  127. data/lib/lookbook/stores/input_store.rb +1 -3
  128. data/lib/lookbook/stores/panel_store.rb +28 -50
  129. data/lib/lookbook/support/deprecation.rb +5 -0
  130. data/lib/lookbook/support/errors/preview_template_error.rb +7 -0
  131. data/lib/lookbook/support/evented_file_update_checker.rb +69 -0
  132. data/lib/lookbook/support/null_websocket.rb +9 -0
  133. data/lib/lookbook/support/store.rb +9 -0
  134. data/lib/lookbook/support/tree_node.rb +7 -7
  135. data/lib/lookbook/support/utils/path_utils.rb +7 -1
  136. data/lib/lookbook/support/utils/utils.rb +8 -0
  137. data/lib/lookbook/tags/{position_tag.rb → priority_tag.rb} +4 -4
  138. data/lib/lookbook/tags/renders_tag.rb +4 -0
  139. data/lib/lookbook/tags/tag_provider.rb +3 -0
  140. data/lib/lookbook/tags/type_tag.rb +7 -0
  141. data/lib/lookbook/tags/yard_tag.rb +1 -2
  142. data/lib/lookbook/version.rb +1 -1
  143. data/lib/lookbook/websocket.rb +6 -53
  144. data/lib/lookbook.rb +179 -53
  145. data/public/lookbook-assets/css/lookbook.css +432 -376
  146. data/public/lookbook-assets/css/lookbook.css.map +1 -1
  147. data/public/lookbook-assets/css/themes/blue.css +7 -0
  148. data/public/lookbook-assets/css/themes/blue.css.map +1 -1
  149. data/public/lookbook-assets/css/themes/green.css +7 -0
  150. data/public/lookbook-assets/css/themes/green.css.map +1 -1
  151. data/public/lookbook-assets/css/themes/indigo.css +7 -0
  152. data/public/lookbook-assets/css/themes/indigo.css.map +1 -1
  153. data/public/lookbook-assets/css/themes/rose.css +7 -0
  154. data/public/lookbook-assets/css/themes/rose.css.map +1 -1
  155. data/public/lookbook-assets/css/themes/zinc.css +7 -0
  156. data/public/lookbook-assets/css/themes/zinc.css.map +1 -1
  157. data/public/lookbook-assets/img/lucide-sprite.svg +4960 -0
  158. data/public/lookbook-assets/js/embed.js +1363 -843
  159. data/public/lookbook-assets/js/embed.js.map +1 -1
  160. data/public/lookbook-assets/js/iframe.js +906 -0
  161. data/public/lookbook-assets/js/iframe.js.map +1 -0
  162. data/public/lookbook-assets/js/index.js +13567 -0
  163. data/public/lookbook-assets/js/index.js.map +1 -0
  164. data/public/lookbook-assets/js/lookbook-core.js +85 -0
  165. data/public/lookbook-assets/js/lookbook-core.js.map +1 -0
  166. data/public/lookbook-assets/js/lookbook.js +151 -12726
  167. data/public/lookbook-assets/js/lookbook.js.map +1 -1
  168. data/public/lookbook-assets/lookbook-esm.js +1427 -0
  169. data/public/lookbook-assets/lookbook-esm.js.map +1 -0
  170. data/public/lookbook-assets/lookbook-global.js +1427 -0
  171. data/public/lookbook-assets/lookbook-global.js.map +1 -0
  172. data/public/lookbook-assets/lookbook.js +1427 -0
  173. data/public/lookbook-assets/lookbook.js.map +1 -0
  174. metadata +85 -77
  175. data/app/components/lookbook/embed/component.js +0 -39
  176. data/app/helpers/lookbook/component_helper.rb +0 -84
  177. data/app/helpers/lookbook/output_helper.rb +0 -19
  178. data/app/helpers/lookbook/page_helper.rb +0 -34
  179. data/app/views/layouts/lookbook/inspector.html.erb +0 -7
  180. data/app/views/layouts/lookbook/page.html.erb +0 -53
  181. data/app/views/layouts/lookbook/standalone.html.erb +0 -5
  182. data/app/views/lookbook/preview.html.erb +0 -14
  183. data/lib/lookbook/entities/collections/component_collection.rb +0 -4
  184. data/lib/lookbook/entities/collections/preview_example_collection.rb +0 -4
  185. data/lib/lookbook/entities/component.rb +0 -31
  186. data/lib/lookbook/entities/concerns/navigable.rb +0 -43
  187. data/lib/lookbook/entities/preview.rb +0 -87
  188. data/lib/lookbook/entities/preview_example.rb +0 -104
  189. data/lib/lookbook/entities/preview_group.rb +0 -52
  190. data/lib/lookbook/preview_actions.rb +0 -43
  191. data/lib/lookbook/process.rb +0 -21
  192. data/lib/lookbook/rendered_example.rb +0 -37
  193. data/lib/lookbook/services/position_prefix_parser.rb +0 -16
  194. data/lib/lookbook/services/urls/search_param_builder.rb +0 -13
  195. data/lib/lookbook/tags/component_tag.rb +0 -13
  196. /data/app/assets/lookbook/js/{embed.js → iframe.js} +0 -0
  197. /data/{app/channels/lookbook → lib/lookbook/cable}/connection.rb +0 -0
  198. /data/{app/channels/lookbook → lib/lookbook/cable}/reload_channel.rb +0 -0
@@ -21,7 +21,7 @@ export default function app() {
21
21
 
22
22
  init() {
23
23
  if (window.SOCKET_PATH) {
24
- console.log("SOCKET CREATED");
24
+ this.debug(`Lookbook socket created`);
25
25
  const socket = createSocket(window.SOCKET_PATH);
26
26
  socket.addListener("Lookbook::ReloadChannel", () => this.updateDOM());
27
27
  }
@@ -43,9 +43,19 @@ export default function app() {
43
43
 
44
44
  hijax(evt) {
45
45
  const link = evt.target.closest("a[href]");
46
- if (link && !isExternalLink(link)) {
47
- evt.preventDefault();
48
- this.navigateTo(link.href);
46
+ if (link) {
47
+ const external = isExternalLink(link);
48
+ const embedded = this.isEmbedded();
49
+
50
+ if (embedded && (!link.hasAttribute("target") || external)) {
51
+ evt.preventDefault();
52
+ window.top.location = link.href;
53
+ return;
54
+ } else if (!embedded && !external && !link.hasAttribute("target")) {
55
+ evt.preventDefault();
56
+ this.navigateTo(link.href);
57
+ return;
58
+ }
49
59
  }
50
60
  },
51
61
 
@@ -89,6 +99,14 @@ export default function app() {
89
99
  }
90
100
  },
91
101
 
102
+ isEmbedded() {
103
+ try {
104
+ return window.self !== window.top;
105
+ } catch (e) {
106
+ return true;
107
+ }
108
+ },
109
+
92
110
  ...Alpine.$log,
93
111
  };
94
112
  }
@@ -5,12 +5,12 @@ function morph(from, to) {
5
5
  },
6
6
  lookahead: true,
7
7
  updating(el, toEl, childrenOnly, skip) {
8
- if (
9
- el.getAttribute &&
10
- el.getAttribute("data-morph-strategy") === "replace"
11
- ) {
8
+ if (!el.getAttribute) return;
9
+ if (el.getAttribute("data-morph-strategy") === "replace") {
12
10
  el.innerHTML = toEl.innerHTML;
13
11
  return skip();
12
+ } else if (el.getAttribute("data-morph-strategy") === "skip") {
13
+ return skip();
14
14
  }
15
15
  },
16
16
  });
@@ -33,9 +33,6 @@ function getElementSize(el, opts = {}) {
33
33
  }
34
34
 
35
35
  function isExternalLink(link) {
36
- if (link.getAttribute("target") === "_blank") {
37
- return true;
38
- }
39
36
  if (link.href) {
40
37
  return link.host !== window.location.host;
41
38
  }
@@ -9,20 +9,13 @@ function prefixString(string, prefix = null) {
9
9
  }
10
10
 
11
11
  function parseSearchParamValue(value) {
12
- const params = {};
13
- value.split("|").forEach((pair_str) => {
14
- const [key, value] = pair_str.split(":").map((part) => part.trim());
15
- params[key] = value;
16
- });
17
- return params;
12
+ const json = decodeURIComponent(value);
13
+ return JSON.parse(json);
18
14
  }
19
15
 
20
16
  function buildSearchParamValue(data) {
21
- const pairs = [];
22
- for (const [key, value] of Object.entries(data)) {
23
- pairs.push(`${key}:${value}`);
24
- }
25
- return pairs.join("|");
17
+ const str = JSON.stringify(data);
18
+ return encodeURIComponent(str);
26
19
  }
27
20
 
28
21
  export {
@@ -0,0 +1,61 @@
1
+ import Alpine from "alpinejs";
2
+
3
+ import Morph from "@alpinejs/morph";
4
+ import Persist from "@alpinejs/persist";
5
+ import Collapse from "@alpinejs/morph";
6
+ import Tooltip from "@ryangjchandler/alpine-tooltip";
7
+
8
+ import Logger, { log } from "./plugins/logger";
9
+
10
+ import initLayoutStore from "./stores/layout";
11
+ import initNavStore from "./stores/nav";
12
+ import initInspectorStore from "./stores/inspector";
13
+ import initPagesStore from "./stores/pages";
14
+ import initSettingsStore from "./stores/settings";
15
+ import initWorkbenchStore from "./stores/workbench";
16
+
17
+ import app from "./app";
18
+
19
+ // Note: A ParcelJS issue prevents loading all depths of component JS files in one glob,
20
+ // so need to split it up. Path aliases also do not work with the glob imports.
21
+ import { getComponents } from "./helpers/build";
22
+ import * as components from "../../../components/lookbook/*/*component.js";
23
+ import * as subComponents from "../../../components/lookbook/*/*/component.js";
24
+ import * as jsComponents from "./components/*.js";
25
+
26
+ // Plugins
27
+
28
+ Alpine.plugin(Morph);
29
+ Alpine.plugin(Persist);
30
+ Alpine.plugin(Collapse);
31
+ Alpine.plugin(Tooltip);
32
+ Alpine.plugin(Logger);
33
+
34
+ // Stores
35
+ const prefix = window.APP_NAME;
36
+ Alpine.store("layout", initLayoutStore(Alpine, { prefix }));
37
+ Alpine.store("nav", initNavStore(Alpine, { prefix }));
38
+ Alpine.store("inspector", initInspectorStore(Alpine, { prefix }));
39
+ Alpine.store("pages", initPagesStore(Alpine, { prefix }));
40
+ Alpine.store("settings", initSettingsStore(Alpine, { prefix }));
41
+
42
+ if (process.env.NODE_ENV !== "production") {
43
+ Alpine.store("workbench", initWorkbenchStore(Alpine, { prefix }));
44
+ }
45
+
46
+ // Components
47
+
48
+ Alpine.data("app", app);
49
+
50
+ [components, subComponents, jsComponents].forEach((scripts) => {
51
+ const components = getComponents(scripts);
52
+ Object.keys(components).forEach((name) => {
53
+ Alpine.data(`${name}Component`, components[name]);
54
+ });
55
+ });
56
+
57
+ // Init
58
+
59
+ window.log = log;
60
+ window.Alpine = Alpine;
61
+ Alpine.start();
@@ -0,0 +1,113 @@
1
+ window.Lookbook = window.Lookbook || {};
2
+ window.Lookbook.initEmbeds = initEmbeds;
3
+
4
+ const embedUrlPrefix = "embed";
5
+ const whiteListedAttributes = [
6
+ "preview",
7
+ "scenario",
8
+ "panels",
9
+ "actions",
10
+ "param-*",
11
+ ];
12
+
13
+ function initEmbeds() {
14
+ if (typeof window.iFrameResize !== "function") {
15
+ console.error(
16
+ "Lookbook embeds require the 'iframe-resizer' library to be available. Skipping embed instantiation."
17
+ );
18
+ return;
19
+ }
20
+
21
+ const embeds = Array.from(document.querySelectorAll("lookbook-embed"));
22
+
23
+ embeds.forEach((embed) => {
24
+ const attrs = Array.from(embed.attributes);
25
+ const wrapper = createWrapper();
26
+ const iframe = createIframe(attrs);
27
+
28
+ wrapper.appendChild(iframe);
29
+ embed.replaceWith(wrapper);
30
+ });
31
+
32
+ window.iFrameResize({ checkOrigin: false }, "[data-lookbook-embed-iframe]");
33
+ }
34
+
35
+ function createWrapper() {
36
+ const wrapper = document.createElement("div");
37
+
38
+ wrapper.setAttribute("data-lookbook-embed", "");
39
+ wrapper.classList.add("lookbook-embed");
40
+
41
+ return wrapper;
42
+ }
43
+
44
+ function createIframe(attrs) {
45
+ const src = buildSrc(attrs);
46
+ const id = attrValue(attrs, "id");
47
+ const styles = attrValue(attrs, "style");
48
+ const classes = attrValue(attrs, "class", "")
49
+ .split(" ")
50
+ .map((c) => c.trim())
51
+ .filter((c) => c.length);
52
+
53
+ const iframe = document.createElement("iframe");
54
+ iframe.src = src;
55
+ if (id) iframe.id = id;
56
+
57
+ iframe.setAttribute("frameborder", 0);
58
+ iframe.setAttribute("data-lookbook-embed-iframe", "");
59
+
60
+ if (classes.length) iframe.classList.add(...classes);
61
+ if (styles) iframe.style.cssText = styles;
62
+
63
+ iframe.style.width = "100%";
64
+ iframe.style.transition = "height 0.3s";
65
+
66
+ return iframe;
67
+ }
68
+
69
+ function buildSrc(attrs) {
70
+ const appPath = attrValue(attrs, "app") || guessBasePath();
71
+ const props = {};
72
+
73
+ permittedAttrs(attrs).forEach(({ name, value }) => {
74
+ name = name.replace("-", "_").toLowerCase();
75
+ props[name] = value;
76
+ });
77
+
78
+ return encodeURI(
79
+ [appPath, embedUrlPrefix].join("/") + `?props=${JSON.stringify(props)}`
80
+ );
81
+ }
82
+
83
+ function attrValue(attrs, name, fallback = null) {
84
+ const attr = attrs.find((attr) => attr.name === name);
85
+ return attr ? attr.value : fallback;
86
+ }
87
+
88
+ function permittedAttrs(attrs) {
89
+ return attrs.filter((attr) => {
90
+ return whiteListedAttributes.find((key) => {
91
+ const name = attr.name;
92
+ return (
93
+ key === name ||
94
+ (key.includes("*") && name.startsWith(key.replace("*", "")))
95
+ );
96
+ });
97
+ });
98
+ }
99
+
100
+ function guessBasePath() {
101
+ const script =
102
+ document.currentScript ||
103
+ document.querySelector('script[src*="lookbook.js"]');
104
+ const scriptSrc = script.src;
105
+
106
+ if (scriptSrc && scriptSrc.includes("lookbook-assets")) {
107
+ return scriptSrc.replace("lookbook-assets/js/lookbook.js", "lookbook");
108
+ }
109
+
110
+ return `//${location.host}/lookbook`;
111
+ }
112
+
113
+ document.addEventListener("DOMContentLoaded", () => initEmbeds());
@@ -3,6 +3,7 @@ import tippy from "tippy.js";
3
3
  tippy.setDefaultProps({
4
4
  allowHTML: true,
5
5
  theme: "tooltip",
6
+ appendTo: document.getElementById("app"),
6
7
  });
7
8
 
8
9
  export default tippy;
@@ -0,0 +1 @@
1
+ import "./lib/lookbook";
@@ -1,61 +1,2 @@
1
- import Alpine from "alpinejs";
2
-
3
- import Morph from "@alpinejs/morph";
4
- import Persist from "@alpinejs/persist";
5
- import Collapse from "@alpinejs/morph";
6
- import Tooltip from "@ryangjchandler/alpine-tooltip";
7
-
8
- import Logger, { log } from "./plugins/logger";
9
-
10
- import initLayoutStore from "./stores/layout";
11
- import initNavStore from "./stores/nav";
12
- import initInspectorStore from "./stores/inspector";
13
- import initPagesStore from "./stores/pages";
14
- import initSettingsStore from "./stores/settings";
15
- import initWorkbenchStore from "./stores/workbench";
16
-
17
- import app from "./app";
18
-
19
- // Note: A ParcelJS issue prevents loading all depths of component JS files in one glob,
20
- // so need to split it up. Path aliases also do not work with the glob imports.
21
- import { getComponents } from "./helpers/build";
22
- import * as components from "../../../components/lookbook/*/*component.js";
23
- import * as subComponents from "../../../components/lookbook/*/*/component.js";
24
- import * as jsComponents from "./components/*.js";
25
-
26
- // Plugins
27
-
28
- Alpine.plugin(Morph);
29
- Alpine.plugin(Persist);
30
- Alpine.plugin(Collapse);
31
- Alpine.plugin(Tooltip);
32
- Alpine.plugin(Logger);
33
-
34
- // Stores
35
- const prefix = window.APP_NAME;
36
- Alpine.store("layout", initLayoutStore(Alpine, { prefix }));
37
- Alpine.store("nav", initNavStore(Alpine, { prefix }));
38
- Alpine.store("inspector", initInspectorStore(Alpine, { prefix }));
39
- Alpine.store("pages", initPagesStore(Alpine, { prefix }));
40
- Alpine.store("settings", initSettingsStore(Alpine, { prefix }));
41
-
42
- if (process.env.NODE_ENV !== "production") {
43
- Alpine.store("workbench", initWorkbenchStore(Alpine, { prefix }));
44
- }
45
-
46
- // Components
47
-
48
- Alpine.data("app", app);
49
-
50
- [components, subComponents, jsComponents].forEach((scripts) => {
51
- const components = getComponents(scripts);
52
- Object.keys(components).forEach((name) => {
53
- Alpine.data(`${name}Component`, components[name]);
54
- });
55
- });
56
-
57
- // Init
58
-
59
- window.log = log;
60
- window.Alpine = Alpine;
61
- Alpine.start();
1
+ import "iframe-resizer/js/iframeResizer";
2
+ import "./lib/lookbook";
@@ -1,6 +1,8 @@
1
1
  module Lookbook
2
2
  class BaseComponent < ViewComponent::Base
3
- include Lookbook::ComponentHelper
3
+ include Lookbook::Engine.routes.url_helpers
4
+ include Lookbook::UiElementsHelper
5
+ include Lookbook::ClassNamesHelper if Engine.runtime_context.rails_older_than?("6.1.0")
4
6
 
5
7
  def initialize(alpine_data: [], **html_attrs)
6
8
  @alpine_data ||= alpine_data
@@ -1,28 +1,17 @@
1
- <%= render_component_tag tag_name,
2
- href: @href,
3
- class: [
4
- "block text-lookbook-icon-button-stroke focus:outline-none focus-visible:outline-none #{padding}",
5
- {
6
- "hover:text-lookbook-icon-button-stroke-hover": !@disabled,
7
- "cursor-[not-allowed] opacity-50": @disabled
8
- }
9
- ],
10
- disabled: @disabled,
1
+ <%= lookbook_render button_component.new(
2
+ id: id,
3
+ icon: icon,
4
+ **button_attrs,
11
5
  "@keydown.esc.stop": "hideDropdown",
12
- "@navigation:complete.window": "updateDropdown" do %>
13
- <span x-ref="icon">
14
- <%= icon || lookbook_render(:icon, name: @icon, size: icon_size, ":class": "{'animate-spin': _spinning}") %>
15
- </span>
16
- <% if @tooltip %>
17
- <label class="hidden" x-ref="tooltip"><%= @tooltip %></label>
18
- <% end %>
19
- <% if content %>
20
- <div x-ref="content"><%== content %></div>
21
- <% end %>
22
- <% if dropdown? %>
23
- <div class="hidden" x-ref="dropdown">
24
- <div class="bg-white divide-y divide-lookbook-divider text-left">
25
- <%== dropdown %>
6
+ "@navigation:complete.window": "updateDropdown") do %>
7
+ <%= content %>
8
+ <% end %>
9
+
10
+ <% if dropdown? %>
11
+ <% content_for :dropdowns do %>
12
+ <div data-dropdown-id="<%= id %>">
13
+ <div class="divide-y divide-lookbook-divider text-left">
14
+ <%= dropdown %>
26
15
  </div>
27
16
  </div>
28
17
  <% end %>
@@ -13,9 +13,9 @@ export default function buttonComponent() {
13
13
  });
14
14
  }
15
15
 
16
- if (this.$refs.dropdown) {
16
+ if (this.dropdownContent) {
17
17
  dropdown = tippy(this.$el, {
18
- content: this.$refs.dropdown.innerHTML,
18
+ content: this.dropdownContent,
19
19
  trigger: "click",
20
20
  theme: "menu",
21
21
  triggerTarget: this.$el,
@@ -32,6 +32,16 @@ export default function buttonComponent() {
32
32
  }
33
33
  },
34
34
 
35
+ get dropdownContent() {
36
+ if (this.$root && this.$root.id) {
37
+ const dropdown = document.querySelector(
38
+ `[data-dropdown-id="${this.$root.id}"]`
39
+ );
40
+ return dropdown ? dropdown.innerHTML : null;
41
+ }
42
+ return null;
43
+ },
44
+
35
45
  hideDropdown() {
36
46
  if (dropdown) {
37
47
  dropdown.hide();
@@ -42,7 +52,7 @@ export default function buttonComponent() {
42
52
  if (dropdown) {
43
53
  dropdown.hide();
44
54
  this.$nextTick(() => {
45
- dropdown.setContent(this.$refs.dropdown.innerHTML);
55
+ dropdown.setContent(this.dropdownContent);
46
56
  });
47
57
  }
48
58
  },
@@ -1,44 +1,35 @@
1
1
  module Lookbook
2
2
  class Button::Component < Lookbook::BaseComponent
3
- renders_one :icon, Lookbook::Icon::Component
4
3
  renders_one :dropdown
5
4
 
6
- ICON_SIZES = {
7
- xs: 3,
8
- sm: 3.5,
9
- md: 4,
10
- lg: 6
11
- }
5
+ attr_reader :id, :icon, :button_attrs
12
6
 
13
- def initialize(icon: nil, tooltip: nil, disabled: false, size: :md, href: nil, **html_attrs)
7
+ def initialize(id: nil, icon: nil, **html_attrs)
8
+ @id = id
14
9
  @icon = icon
15
- @tooltip = tooltip
16
- @disabled = disabled
17
- @size = size
18
- @href = href
19
- super(**html_attrs)
10
+ @button_attrs = html_attrs
20
11
  end
21
12
 
22
- def icon_size
23
- ICON_SIZES[@size]
13
+ def dropdown?
14
+ dropdown.present?
24
15
  end
25
16
 
26
- def padding
27
- [:xs, :sm].include?(@size) ? "p-1" : "p-2"
17
+ def text_button?
18
+ content.present?
28
19
  end
29
20
 
30
- def tag_name
31
- @href.present? ? :a : :button
21
+ def icon_button?
22
+ !text_button? && icon
32
23
  end
33
24
 
34
- def dropdown?
35
- dropdown.present?
25
+ def before_render
26
+ if dropdown? && id.nil?
27
+ raise "Dropdown buttons must be given an ID"
28
+ end
36
29
  end
37
30
 
38
- protected
39
-
40
- def alpine_component
41
- "buttonComponent"
31
+ def button_component
32
+ icon_button? ? IconButton::Component : TextButton::Component
42
33
  end
43
34
  end
44
35
  end
@@ -1,7 +1,5 @@
1
1
  module Lookbook
2
2
  class Code::Component < Lookbook::BaseComponent
3
- include Lookbook::OutputHelper
4
-
5
3
  def initialize(
6
4
  source: nil,
7
5
  language: :html,
@@ -1,11 +1,11 @@
1
- <%= lookbook_render :button,
1
+ <%= lookbook_render :icon_button,
2
2
  name: "copy-button",
3
- **@button_attrs,
3
+ **button_attrs,
4
4
  "x-data": prepare_alpine_data,
5
5
  "@click.prevent": "copyToClipboard" do |button| %>
6
- <% button.with_icon name: @icon, size: icon_size, "x-show": "!copied", cloak: true %>
7
- <%= icon :check, size: icon_size, class: "text-green-500", "x-show": "copied", cloak: true %>
6
+ <% button.with_icon name: icon, size: icon_size, "x-show": "!copied", cloak: true %>
7
+ <% button.with_icon name: :check, size: icon_size, class: "text-green-500", "x-show": "copied", cloak: true %>
8
8
  <% if content %>
9
9
  <div x-ref="copyTarget" class="hidden"><%== content %></div>
10
10
  <% end %>
11
- <% end %>
11
+ <% end %>
@@ -1,19 +1,22 @@
1
1
  module Lookbook
2
2
  class CopyButton::Component < Lookbook::BaseComponent
3
- def initialize(target: nil, icon: :code, **attrs)
3
+ attr_reader :icon, :size, :target, :button_attrs
4
+
5
+ def initialize(target: nil, icon: :code, size: :md, **attrs)
4
6
  @icon = icon
7
+ @size = size
5
8
  @target = target
6
9
  @button_attrs = attrs
7
10
  end
8
11
 
9
12
  def icon_size
10
- Lookbook::Button::Component::ICON_SIZES[@size]
13
+ IconButton::Component::ICON_SIZES[size]
11
14
  end
12
15
 
13
16
  protected
14
17
 
15
18
  def alpine_data
16
- content ? nil : alpine_encode(@target)
19
+ content ? nil : alpine_encode(target)
17
20
  end
18
21
 
19
22
  def alpine_component
@@ -27,6 +27,7 @@
27
27
  </li>
28
28
  </ul>
29
29
  </div>
30
+
30
31
  <div class="flex items-center text-xs px-3 py-2 bg-zinc-50">
31
32
  <span class="opacity-70 mr-1">Lookbook</span>
32
33
  <span class="mr-6">v<%= @version %></span>
@@ -1,12 +1,23 @@
1
1
  module Lookbook
2
2
  class DebugMenu::Component < Lookbook::BaseComponent
3
- def initialize(version: nil, docs_url: nil, repo_url: nil, **html_attrs)
3
+ attr_reader :features
4
+
5
+ def initialize(version: nil, docs_url: nil, repo_url: nil, features: {}, **html_attrs)
4
6
  @version = version
5
7
  @docs_url = docs_url
6
8
  @repo_url = repo_url
9
+ @features = features
7
10
  super(**html_attrs)
8
11
  end
9
12
 
13
+ def auto_refresh_enabled?
14
+ feature(:auto_refresh, false)
15
+ end
16
+
17
+ def feature(name, fallback = nil)
18
+ features.fetch(name.to_sym, fallback)
19
+ end
20
+
10
21
  def debug_data
11
22
  content
12
23
  end
@@ -1,6 +1,6 @@
1
1
  <%= render_component_tag class: "px-2" do %>
2
2
  <% if fields.many? %>
3
- <%= lookbook_render :button, icon: :settings, tooltip: "Display options" do |button| %>
3
+ <%= lookbook_render :button, id: "display-options-dropdown-button", icon: :settings, tooltip: "Display options" do |button| %>
4
4
  <% button.with_dropdown do %>
5
5
  <div class="p-3 space-y-3">
6
6
  <%= safe_join(fields) %>
@@ -1,33 +1,7 @@
1
1
  @layer components {
2
2
  [data-component="display-options-field"] {
3
- [type="text"],
4
- [type="email"],
5
- [type="url"],
6
- [type="password"],
7
- [type="number"],
8
- [type="date"],
9
- [type="datetime-local"],
10
- [type="month"],
11
- [type="search"],
12
- [type="tel"],
13
- [type="time"],
14
- [type="week"],
15
- textarea,
16
- select {
17
- padding: 0.26rem 0.6rem;
18
- font-size: 0.8rem;
19
- line-height: 1.1rem;
20
- }
21
-
22
3
  label {
23
4
  @apply text-[0.82rem] text-lookbook-input-text cursor-pointer;
24
5
  }
25
-
26
- select {
27
- border-radius: 0.375rem;
28
- padding-right: 1.5rem;
29
- background-size: 1.2em 1.2em;
30
- background-position: right 0.4rem center;
31
- }
32
6
  }
33
7
  }
@@ -3,6 +3,6 @@
3
3
  <label for="<%= name %>">
4
4
  <%= name.to_s.titleize %>:
5
5
  </label>
6
- <%= select_tag(name, options_for_select(choices, value), "x-model": "value") %>
6
+ <%= select_tag(name, options_for_select(choices, value), "x-model": "value", class: "compact") %>
7
7
  </div>
8
8
  <% end %>