@ulu/frontend 0.1.0-beta.32 → 0.1.0-beta.34

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 (214) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/ulu-frontend.min.css +1 -1
  3. package/dist/ulu-frontend.min.js +23 -23
  4. package/docs-dev/changelog/index.html +161 -8
  5. package/docs-dev/demos/accordion/index.html +38 -8
  6. package/docs-dev/demos/button/index.html +38 -8
  7. package/docs-dev/demos/button-verbose/index.html +38 -8
  8. package/docs-dev/demos/callout/index.html +65 -8
  9. package/docs-dev/demos/captioned-figure/index.html +38 -8
  10. package/docs-dev/demos/card/index.html +59 -33
  11. package/docs-dev/demos/card-grid/index.html +42 -12
  12. package/docs-dev/demos/css-icons/index.html +38 -8
  13. package/docs-dev/demos/data-grid/index.html +38 -8
  14. package/docs-dev/demos/data-table/index.html +63 -33
  15. package/docs-dev/demos/details-group/index.html +71 -8
  16. package/docs-dev/demos/file-save/index.html +38 -8
  17. package/docs-dev/demos/flipcard/index.html +38 -8
  18. package/docs-dev/demos/form-theme/index.html +38 -8
  19. package/docs-dev/demos/index.html +38 -8
  20. package/docs-dev/demos/list-inline/index.html +38 -8
  21. package/docs-dev/demos/list-lines/index.html +38 -8
  22. package/docs-dev/demos/menu-stack/index.html +38 -8
  23. package/docs-dev/demos/modals/index.html +51 -10
  24. package/docs-dev/demos/nav-strip/index.html +38 -8
  25. package/docs-dev/demos/overlay-section/index.html +38 -8
  26. package/docs-dev/demos/popovers/index.html +38 -8
  27. package/docs-dev/demos/print/index.html +38 -8
  28. package/docs-dev/demos/pull-quote/index.html +38 -8
  29. package/docs-dev/demos/rule/index.html +38 -8
  30. package/docs-dev/demos/scrollpoints/index.html +39 -9
  31. package/docs-dev/demos/spoke-spinner/index.html +38 -8
  32. package/docs-dev/demos/sticky-list/index.html +38 -8
  33. package/docs-dev/demos/tabs/index.html +74 -8
  34. package/docs-dev/demos/tag/index.html +38 -8
  35. package/docs-dev/demos/theme-toggle/index.html +38 -8
  36. package/docs-dev/demos/tiles/index.html +38 -8
  37. package/docs-dev/demos/tooltip/index.html +38 -8
  38. package/docs-dev/guide/building-stylesheet/index.html +38 -8
  39. package/docs-dev/guide/developing-ulu-scss-module/index.html +38 -8
  40. package/docs-dev/guide/index.html +38 -8
  41. package/docs-dev/index.html +38 -8
  42. package/docs-dev/javascript/events/index.html +38 -8
  43. package/docs-dev/javascript/index.html +38 -8
  44. package/docs-dev/javascript/settings/index.html +38 -8
  45. package/docs-dev/javascript/ui-breakpoints/index.html +38 -8
  46. package/docs-dev/javascript/ui-collapsible/index.html +38 -8
  47. package/docs-dev/javascript/ui-details-group/index.html +56 -38
  48. package/docs-dev/javascript/ui-dialog/index.html +70 -25
  49. package/docs-dev/javascript/ui-flipcard/index.html +99 -13
  50. package/docs-dev/javascript/ui-grid/index.html +48 -44
  51. package/docs-dev/javascript/ui-modal-builder/index.html +49 -40
  52. package/docs-dev/javascript/ui-overflow-scroller/index.html +38 -8
  53. package/docs-dev/javascript/ui-overflow-scroller-pager/index.html +38 -8
  54. package/docs-dev/javascript/ui-page/index.html +38 -8
  55. package/docs-dev/javascript/ui-popover/index.html +46 -20
  56. package/docs-dev/javascript/ui-print/index.html +38 -16
  57. package/docs-dev/javascript/ui-print-details/index.html +38 -8
  58. package/docs-dev/javascript/ui-programmatic-modal/index.html +38 -8
  59. package/docs-dev/javascript/ui-proxy-click/index.html +125 -10
  60. package/docs-dev/javascript/ui-resizer/index.html +38 -8
  61. package/docs-dev/javascript/ui-scroll-slider/index.html +76 -14
  62. package/docs-dev/javascript/ui-scrollpoint/index.html +44 -21
  63. package/docs-dev/javascript/ui-slider/index.html +234 -13
  64. package/docs-dev/javascript/ui-tabs/index.html +49 -56
  65. package/docs-dev/javascript/ui-theme-toggle/index.html +43 -21
  66. package/docs-dev/javascript/ui-tooltip/index.html +45 -19
  67. package/docs-dev/javascript/utils-class-logger/index.html +38 -8
  68. package/docs-dev/javascript/utils-dom/index.html +63 -8
  69. package/docs-dev/javascript/utils-file-save/index.html +38 -8
  70. package/docs-dev/javascript/utils-floating-ui/index.html +38 -8
  71. package/docs-dev/javascript/utils-id/index.html +38 -8
  72. package/docs-dev/javascript/utils-pause-youtube-video/index.html +38 -8
  73. package/docs-dev/javascript/utils-system/index.html +5437 -0
  74. package/docs-dev/sass/base/color/index.html +38 -8
  75. package/docs-dev/sass/base/elements/index.html +38 -8
  76. package/docs-dev/sass/base/index/index.html +38 -8
  77. package/docs-dev/sass/base/index.html +38 -8
  78. package/docs-dev/sass/base/keyframes/index.html +38 -8
  79. package/docs-dev/sass/base/layout/index.html +38 -8
  80. package/docs-dev/sass/base/normalize/index.html +38 -8
  81. package/docs-dev/sass/base/print/index.html +38 -8
  82. package/docs-dev/sass/base/root/index.html +38 -8
  83. package/docs-dev/sass/base/typography/index.html +38 -8
  84. package/docs-dev/sass/components/accordion/index.html +39 -9
  85. package/docs-dev/sass/components/adaptive-spacing/index.html +38 -8
  86. package/docs-dev/sass/components/badge/index.html +38 -8
  87. package/docs-dev/sass/components/basic-hero/index.html +38 -8
  88. package/docs-dev/sass/components/button/index.html +38 -8
  89. package/docs-dev/sass/components/button-verbose/index.html +72 -37
  90. package/docs-dev/sass/components/callout/index.html +124 -35
  91. package/docs-dev/sass/components/captioned-figure/index.html +38 -8
  92. package/docs-dev/sass/components/card/index.html +38 -8
  93. package/docs-dev/sass/components/card-grid/index.html +38 -8
  94. package/docs-dev/sass/components/css-icon/index.html +38 -8
  95. package/docs-dev/sass/components/data-grid/index.html +38 -8
  96. package/docs-dev/sass/components/data-table/index.html +53 -16
  97. package/docs-dev/sass/components/fill-context/index.html +38 -8
  98. package/docs-dev/sass/components/flipcard/index.html +38 -8
  99. package/docs-dev/sass/components/flipcard-grid/index.html +38 -8
  100. package/docs-dev/sass/components/form-theme/index.html +84 -60
  101. package/docs-dev/sass/components/hero/index.html +38 -8
  102. package/docs-dev/sass/components/horizontal-rule/index.html +38 -8
  103. package/docs-dev/sass/components/image-grid/index.html +38 -8
  104. package/docs-dev/sass/components/index/index.html +38 -8
  105. package/docs-dev/sass/components/index.html +38 -8
  106. package/docs-dev/sass/components/links/index.html +38 -8
  107. package/docs-dev/sass/components/list-inline/index.html +38 -8
  108. package/docs-dev/sass/components/list-lines/index.html +38 -8
  109. package/docs-dev/sass/components/list-ordered/index.html +38 -8
  110. package/docs-dev/sass/components/list-unordered/index.html +38 -8
  111. package/docs-dev/sass/components/menu-stack/index.html +38 -8
  112. package/docs-dev/sass/components/modal/index.html +38 -8
  113. package/docs-dev/sass/components/nav-strip/index.html +38 -8
  114. package/docs-dev/sass/components/overlay-section/index.html +38 -8
  115. package/docs-dev/sass/components/pager/index.html +38 -8
  116. package/docs-dev/sass/components/placeholder-block/index.html +38 -8
  117. package/docs-dev/sass/components/popover/index.html +38 -8
  118. package/docs-dev/sass/components/pull-quote/index.html +38 -8
  119. package/docs-dev/sass/components/ratio-box/index.html +38 -8
  120. package/docs-dev/sass/components/rule/index.html +38 -8
  121. package/docs-dev/sass/components/scroll-slider/index.html +46 -28
  122. package/docs-dev/sass/components/skip-link/index.html +38 -8
  123. package/docs-dev/sass/components/slider/index.html +38 -8
  124. package/docs-dev/sass/components/spoke-spinner/index.html +40 -10
  125. package/docs-dev/sass/components/sticky-list/index.html +38 -8
  126. package/docs-dev/sass/components/tabs/index.html +38 -8
  127. package/docs-dev/sass/components/tag/index.html +40 -10
  128. package/docs-dev/sass/components/tile-button/index.html +38 -8
  129. package/docs-dev/sass/components/tile-grid/index.html +38 -8
  130. package/docs-dev/sass/components/tile-grid-overlay/index.html +38 -8
  131. package/docs-dev/sass/components/vignette/index.html +38 -8
  132. package/docs-dev/sass/components/wysiwyg/index.html +38 -8
  133. package/docs-dev/sass/core/breakpoint/index.html +38 -8
  134. package/docs-dev/sass/core/button/index.html +38 -8
  135. package/docs-dev/sass/core/color/index.html +38 -8
  136. package/docs-dev/sass/core/cssvar/index.html +38 -8
  137. package/docs-dev/sass/core/element/index.html +218 -47
  138. package/docs-dev/sass/core/index.html +38 -8
  139. package/docs-dev/sass/core/layout/index.html +94 -45
  140. package/docs-dev/sass/core/path/index.html +38 -8
  141. package/docs-dev/sass/core/selector/index.html +38 -8
  142. package/docs-dev/sass/core/typography/index.html +38 -8
  143. package/docs-dev/sass/core/units/index.html +38 -8
  144. package/docs-dev/sass/core/utils/index.html +302 -68
  145. package/docs-dev/sass/helpers/color/index.html +38 -8
  146. package/docs-dev/sass/helpers/display/index.html +38 -8
  147. package/docs-dev/sass/helpers/index/index.html +38 -8
  148. package/docs-dev/sass/helpers/index.html +38 -8
  149. package/docs-dev/sass/helpers/print/index.html +38 -8
  150. package/docs-dev/sass/helpers/typography/index.html +38 -8
  151. package/docs-dev/sass/helpers/units/index.html +38 -8
  152. package/docs-dev/sass/helpers/utilities/index.html +38 -8
  153. package/docs-dev/sass/index.html +38 -8
  154. package/js/ui/breakpoints.js +1 -2
  155. package/js/ui/details-group.js +33 -42
  156. package/js/ui/dialog.js +64 -41
  157. package/js/ui/dialog.todo +2 -36
  158. package/js/ui/flipcard.js +37 -57
  159. package/js/ui/grid.js +15 -13
  160. package/js/ui/modal-builder.js +24 -38
  161. package/js/ui/popover.js +38 -39
  162. package/js/ui/print.js +16 -25
  163. package/js/ui/proxy-click.js +50 -36
  164. package/js/ui/scroll-slider.js +24 -30
  165. package/js/ui/scrollpoint.js +27 -63
  166. package/js/ui/slider.js +53 -55
  167. package/js/ui/tabs.js +23 -36
  168. package/js/ui/theme-toggle.js +37 -41
  169. package/js/ui/tooltip.js +27 -32
  170. package/js/utils/dom.js +12 -0
  171. package/js/utils/system.js +154 -0
  172. package/package.json +1 -1
  173. package/scss/_element.scss +91 -0
  174. package/scss/_layout.scss +3 -1
  175. package/scss/_utils.scss +42 -0
  176. package/scss/components/_accordion.scss +1 -2
  177. package/scss/components/_button-verbose.scss +41 -36
  178. package/scss/components/_callout.scss +113 -53
  179. package/scss/components/_data-table.scss +3 -0
  180. package/scss/components/_form-theme.scss +24 -25
  181. package/scss/components/_scroll-slider.scss +0 -4
  182. package/types/ui/breakpoints.d.ts.map +1 -1
  183. package/types/ui/details-group.d.ts +7 -12
  184. package/types/ui/details-group.d.ts.map +1 -1
  185. package/types/ui/dialog.d.ts +19 -14
  186. package/types/ui/dialog.d.ts.map +1 -1
  187. package/types/ui/flipcard.d.ts +16 -10
  188. package/types/ui/flipcard.d.ts.map +1 -1
  189. package/types/ui/grid.d.ts +4 -6
  190. package/types/ui/grid.d.ts.map +1 -1
  191. package/types/ui/modal-builder.d.ts +5 -9
  192. package/types/ui/modal-builder.d.ts.map +1 -1
  193. package/types/ui/popover.d.ts +6 -7
  194. package/types/ui/popover.d.ts.map +1 -1
  195. package/types/ui/print.d.ts +0 -4
  196. package/types/ui/print.d.ts.map +1 -1
  197. package/types/ui/proxy-click.d.ts +19 -3
  198. package/types/ui/proxy-click.d.ts.map +1 -1
  199. package/types/ui/scroll-slider.d.ts +5 -7
  200. package/types/ui/scroll-slider.d.ts.map +1 -1
  201. package/types/ui/scrollpoint.d.ts +3 -8
  202. package/types/ui/scrollpoint.d.ts.map +1 -1
  203. package/types/ui/slider.d.ts +22 -12
  204. package/types/ui/slider.d.ts.map +1 -1
  205. package/types/ui/tabs.d.ts +6 -8
  206. package/types/ui/tabs.d.ts.map +1 -1
  207. package/types/ui/theme-toggle.d.ts +6 -13
  208. package/types/ui/theme-toggle.d.ts.map +1 -1
  209. package/types/ui/tooltip.d.ts +3 -5
  210. package/types/ui/tooltip.d.ts.map +1 -1
  211. package/types/utils/dom.d.ts +6 -0
  212. package/types/utils/dom.d.ts.map +1 -1
  213. package/types/utils/system.d.ts +113 -0
  214. package/types/utils/system.d.ts.map +1 -0
package/js/utils/dom.js CHANGED
@@ -5,6 +5,18 @@
5
5
 
6
6
  export const regexJsonString = /^[{\[][\s\S]*[}\]]$/;
7
7
 
8
+ /**
9
+ * Converts a data attribute name to its corresponding dataset property name.
10
+ * @param {string} dataAttribute - The data attribute name (e.g., "data-ulu-dialog").
11
+ * @returns {string} - The dataset property name (e.g., "uluDialog").
12
+ */
13
+ export function dataAttributeToDatasetKey(attribute) {
14
+ // Remove "data-" prefix then convert kebab-case to camelCase
15
+ return attribute
16
+ .replace(/^data-/, "")
17
+ .replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
18
+ }
19
+
8
20
  /**
9
21
  * Get an elements JSON dataset value
10
22
  * @param {Node} element
@@ -0,0 +1,154 @@
1
+ /**
2
+ * @module utils/system
3
+ * @description Core classes and mechanisms that define how UI components are created and managed within the library
4
+ */
5
+
6
+ import { hasRequiredProps } from "@ulu/utils/object.js";
7
+ import { getDatasetOptionalJson, dataAttributeToDatasetKey } from "./dom.js";
8
+ import { getName } from "../events/index.js";
9
+
10
+ /**
11
+ * Class serves as a utility for UI modules, handling the selection of elements and the initialization of corresponding component instances, ensuring consistent setup within the module
12
+ */
13
+ export class ComponentInitializer {
14
+ static defaults = {
15
+ type: null,
16
+ baseAttribute: null
17
+ };
18
+ static requiredOptions = [
19
+ "type",
20
+ "baseAttribute"
21
+ ];
22
+ static hasRequiredOptions = hasRequiredProps(
23
+ ComponentInitializer.requiredOptions
24
+ );
25
+
26
+ /**
27
+ * Create a new instance of ComponentInitializer
28
+ * @param {Object} options Options for configuring the component initializer.
29
+ * @param {String} options.type Type of component (used for logs).
30
+ * @param {String} options.baseAttribute Prefix and base attribute name (used for base attribute and further element attribute names).
31
+ */
32
+ constructor(options) {
33
+ if (!ComponentInitializer.hasRequiredOptions(options)) {
34
+ throw new Error(
35
+ `Missing a required options: ${ ComponentInitializer.requiredOptions.join(", ") }`
36
+ );
37
+ }
38
+ this.options = Object.assign({}, ComponentInitializer.defaults, options);
39
+ this.logTitle = `ULU: ${ this.options.type }:\n`;
40
+ }
41
+ /**
42
+ * Initializes the component based on the provided configuration.
43
+ * @param {Object} config The initialization configuration.
44
+ * @param {Function} config.setup The setup function to call for each element.
45
+ * @param {String} config.key [null] The optional key to use with attribute selector.
46
+ * @param {Boolean} config.withData [null] Whether to retrieve element data.
47
+ * @param {Array} config.events [null] Ulu events that should call setup when dispatched (ie. pageModified, pageResized)
48
+ * @param {Boolean} config.onPageResized [null] Whether to bind event listener for page resize end
49
+ * @param {HTMLElement} config.context [document] The context to query within.
50
+ */
51
+ init(config) {
52
+ this.setupElements(config);
53
+ // Attach Handler to reinitialize if page is updated
54
+ // Specifically checking entire document incase element that dispatched
55
+ // event made alterations outside of itself
56
+ if (config.events?.length) {
57
+ config.events.forEach(name => {
58
+ document.addEventListener(getName(name), () => this.setupElements(config));
59
+ });
60
+ }
61
+ }
62
+ /**
63
+ * Processes the elements based on the provided configuration.
64
+ * @param {object} config The initialization configuration.
65
+ * @param {function} config.setup The setup function to call for each element.
66
+ * @param {string} config.key The optional key to use with attribute selector.
67
+ * @param {boolean} config.withData [false] Whether to retrieve element data.
68
+ * @param {boolean} config.onPageModified [true] Whether to bind event listener for page modifications.
69
+ * @param {HTMLElement} config.context [document] The context to query within.
70
+ */
71
+ setupElements(config) {
72
+ const { setup, key, withData, context } = config;
73
+ const elementsWithData = this.queryAllInitial(key, withData, context);
74
+ elementsWithData.forEach(elementWithData => setup(elementWithData, this));
75
+ }
76
+ /**
77
+ * Get an attribute name
78
+ * @param {String} key Optional key, if no key will return baseAttribute if key will return key added to base
79
+ * @returns {String} String like data-ulu-dialog or data-ulu-dialog-element
80
+ */
81
+ getAttribute(key) {
82
+ const { baseAttribute } = this.options;
83
+ return key ? `${ baseAttribute }-${ key }` : `${ baseAttribute }`;
84
+ }
85
+ /**
86
+ * Create an attribute selector
87
+ * @param {String} key Optional key (see getAttribute)
88
+ */
89
+ attributeSelector(key) {
90
+ return `[${ this.getAttribute(key) }]`;
91
+ }
92
+ /**
93
+ * Create an attribute selector for initial
94
+ * @return {String}
95
+ */
96
+ attributeSelectorInitial(key) {
97
+ return `${ this.attributeSelector(key) }:not([${ this.getAttribute("init") }])`
98
+ }
99
+ /**
100
+ * Queries all main elements of a component that have not been initialized and extracts their data attributes.
101
+ * @param {HTMLElement} context The context to query within.
102
+ * @param {Boolean} withData Include dataset from element (as optional JSON)
103
+ * @param {Node} context Element to query elements from
104
+ * @returns {Array<{element: HTMLElement, data: object, initialize: Function}>} An array of objects containing the elements, their data, and convenience function initialize() which when called will set the init attribute on the element
105
+ */
106
+ queryAllInitial(key, withData, context = document) {
107
+ const elements = [ ...context.querySelectorAll(this.attributeSelectorInitial(key)) ];
108
+ return elements.map((element) => ({
109
+ element,
110
+ data: withData ? this.getData(element, key) : null,
111
+ initialize: () => this.initializeElement(element)
112
+ }));
113
+ }
114
+ /**
115
+ * Sets the init attribute on an element, marking it as initialized.
116
+ * @param {HTMLElement} element The element to initialize.
117
+ */
118
+ initializeElement(element) {
119
+ element.setAttribute(this.getAttribute("init"), "");
120
+ }
121
+ /**
122
+ * Get an elements dataset value as JSON or other value
123
+ * @return {*} The value of the dataset, if JSON will return object else will return string value or undefined
124
+ */
125
+ getData(element, key) {
126
+ const datasetKey = dataAttributeToDatasetKey(this.getAttribute(key));
127
+ return getDatasetOptionalJson(element, datasetKey);
128
+ }
129
+ /**
130
+ * Will output namespaced console logs for the given initializer
131
+ */
132
+ log(...msgs) {
133
+ console.log(this.logTitle, ...msgs);
134
+ }
135
+ /**
136
+ * Will output namespaced console warnings for the given initializer
137
+ */
138
+ warn(...msgs) {
139
+ console.warn(this.logTitle, ...msgs);
140
+ }
141
+ /**
142
+ * Will output namespaced console error for the given initializer
143
+ */
144
+ logError(...msgs) {
145
+ console.error(this.logTitle, ...msgs);
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Class serves as a base for representing individual occurrences of a UI component, providing a consistent structure for each
151
+ */
152
+ export class ComponentInstance {
153
+
154
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulu/frontend",
3
- "version": "0.1.0-beta.32",
3
+ "version": "0.1.0-beta.34",
4
4
  "description": "Modular Sass Theming Library",
5
5
  "browser": "js/index.js",
6
6
  "main": "index.js",
@@ -69,6 +69,8 @@ $config: (
69
69
  "ul-list-style-type": disc,
70
70
  "ul-list-style-type-2": circle,
71
71
  "ul-list-style-type-3": square,
72
+ "cap-color" : "accent",
73
+ "cap-size" : 5px
72
74
  ) !default;
73
75
 
74
76
  /// Rule style map, redefine defaults or add to
@@ -290,4 +292,93 @@ $rule-margins: (
290
292
  white-space: normal;
291
293
  width: auto;
292
294
  }
295
+ }
296
+
297
+
298
+ /// Layout utility to add a colored bar (cap) to an element's edge, positioned over the element and its border
299
+ /// - You need to set position (relative, fixed) on parent
300
+ /// @param {String} $side The side to place the cap (top, bottom, left, right)
301
+ /// @param {Map} $options Options for the appearance of the cap
302
+ /// @param {Color} $options.color [$config.cap-color] The color for the end cap
303
+ /// @param {Number} $options.size [$config.cap-size] The width/height of the cap
304
+ /// @param {Number} $options.offset [0] A positive number of the amount the cap should extend outside the box (to account for border-width)
305
+ /// @param {Number} $options.border-radius [null] An optional border-radius to apply to the outward-facing edges of the cap (used to match parent)
306
+ /// @param {Boolean} $before [true] Whether or not to use the ::before element (if not uses :after)
307
+
308
+ @mixin cap(
309
+ $side,
310
+ $options: (),
311
+ $before: true,
312
+ ) {
313
+ $defaults: (
314
+ "color" : get("cap-color"),
315
+ "size" : get("cap-size"),
316
+ "offset" : 0,
317
+ "color-hover" : null,
318
+ "border-radius" : null,
319
+ "padding-adjust" : null,
320
+ );
321
+ $config: map.merge($defaults, $options);
322
+ $element: if($before, "::before", "::after");
323
+
324
+ &#{ $element } {
325
+ content: "";
326
+ position: absolute;
327
+ display: block;
328
+ }
329
+
330
+ @include cap-appearance($side, $config, $before);
331
+ }
332
+
333
+
334
+
335
+ /// Provides the appearance styles for a given cap
336
+ /// - If an option is not provided it won't be output
337
+ /// - This is used to update the caps styling (states, modifiers, etc)
338
+ /// @param {String} $side The side to place the cap (top, bottom, left, right)
339
+ /// @param {Map} $options Options for the appearance of the cap (see options from element.cap)
340
+ /// @param {Boolean} $before Whether or not to use the ::before element (if not uses :after)
341
+
342
+ @mixin cap-appearance(
343
+ $side,
344
+ $options: (),
345
+ $before: true
346
+ ) {
347
+ $element: if($before, "::before", "::after");
348
+ $size: map.get($options, "size");
349
+ $offset: map.get($options, "offset");
350
+ $border-radius: map.get($options, "border-radius");
351
+ $padding-adjust: map.get($options, "padding-adjust");
352
+
353
+ $end: $side == "top" or $side == "bottom";
354
+ $position: if($offset, 0 - $offset, null);
355
+
356
+ @if ($padding-adjust and $size) {
357
+ padding-#{ $side }: calc($padding-adjust + $size);
358
+ }
359
+
360
+ &#{ $element } {
361
+ background-color: color.get(map.get($options, "color"));
362
+ #{ $side }: $position;
363
+
364
+ @if $end {
365
+ left: $position;
366
+ right: $position;
367
+ height: $size;
368
+ } @else {
369
+ top: $position;
370
+ bottom: $position;
371
+ width: $size;
372
+ }
373
+
374
+ @if $border-radius {
375
+ @if $end {
376
+ border-#{ $side }-left-radius: $border-radius;
377
+ border-#{ $side }-right-radius: $border-radius;
378
+ } @else {
379
+ border-top-#{ $side }-radius: $border-radius;
380
+ border-bottom-#{ $side }-radius: $border-radius;
381
+ }
382
+ }
383
+ }
293
384
  }
package/scss/_layout.scss CHANGED
@@ -7,6 +7,7 @@
7
7
  @use "sass:meta";
8
8
  @use "utils";
9
9
  @use "breakpoint";
10
+ @use "color";
10
11
 
11
12
  /// Module Settings
12
13
  /// @type Map
@@ -264,6 +265,7 @@ $containers: (
264
265
  /// Layout utility for absolute (zero on all sides)
265
266
  /// - Probably helpful for gzip if we use this when these exact styles are needed
266
267
  /// so they are identical for compression
268
+ /// @param {Boolean} $set-size [false] Whether or not to use sizes to fill the space (height/width 100%) versus setting bottom and right to 0)
267
269
  @mixin absolute-fill($set-size: false) {
268
270
  position: absolute;
269
271
  top: 0;
@@ -275,4 +277,4 @@ $containers: (
275
277
  width: 100%;
276
278
  height: 100%;
277
279
  }
278
- }
280
+ }
package/scss/_utils.scss CHANGED
@@ -161,6 +161,16 @@ $config: (
161
161
  @return $number + string.unquote($unit);
162
162
  }
163
163
 
164
+ /// Checks if two numbers are the same unit
165
+ /// @param {Number} $number
166
+ /// @param {String} $other-number
167
+ /// @return {Boolean} Whether they have the same unit type
168
+ // Could be made into multiple arguments in future if needed
169
+
170
+ @function units-match($number, $other-number) {
171
+ @return math.unit($number) == math.unit($other-number);
172
+ }
173
+
164
174
  /// Reusable merge method
165
175
  /// @param {Map} $original Source map
166
176
  /// @param {Map} $changes Changes to merge into source map
@@ -661,4 +671,36 @@ $config: (
661
671
 
662
672
  @function is-odd($number) {
663
673
  @return not is-even($number);
674
+ }
675
+
676
+ /// Always returns a map
677
+ /// @param {*} $value The value to check if is map
678
+ /// @return {Map} The $value if it was a map, else empty map
679
+
680
+ @function ensure-map($value) {
681
+ @return if(is-map($value), $value, ());
682
+ }
683
+
684
+ /// Returns true if edge passed is an end (top/bottom)
685
+ /// @param {String} $edge The edge string to test
686
+ /// @return {Boolean} Whether the edge was an end (versus side/x-axis)
687
+ /// @throw If $edge is not a valid value (not top/bottom/left/right)
688
+
689
+ @function is-end($edge) {
690
+ @if ($edge == "top" or $edge == "bottom") {
691
+ @return true;
692
+ } @else if ($edge == "left" or $edge == "right") {
693
+ @return false;
694
+ } @else {
695
+ @error "Expected side to be top/bottom/left/right, got #{ $edge }";
696
+ }
697
+ }
698
+
699
+ /// Returns true if edge passed is an side (left/right)
700
+ /// @param {String} $edge The edge string to test
701
+ /// @return {Boolean} Whether the edge was an side (versus end/y-axis)
702
+ /// @throw If $edge is not a valid value (not top/bottom/left/right)
703
+
704
+ @function is-side($edge) {
705
+ @return not is-end($edge);
664
706
  }
@@ -120,7 +120,7 @@ $config: (
120
120
  & + & {
121
121
  $gap: -(get("margin") - get("margin-between"));
122
122
  margin-top: $gap;
123
- margin-top: calc($gap - 1px);
123
+ margin-top: calc($gap - get("border-width"));
124
124
  }
125
125
  &[open],
126
126
  &.is-active {
@@ -208,7 +208,6 @@ $config: (
208
208
  }
209
209
  #{ $prefix }--no-borders {
210
210
  border: none;
211
- margin-bottom: 4rem;
212
211
  &[open] > .accordion__summary {
213
212
  border-bottom: none;
214
213
  }
@@ -48,11 +48,11 @@ $-fallbacks: (
48
48
  /// @prop {String} title-color [link] Color of the title of the button.
49
49
  /// @prop {String} title-color-hover [link-hover] Color of the title of the button when hovered or focused.
50
50
  /// @prop {Dimension} title-margin [0.5em] Margin for the button's title.
51
- /// @prop {Boolean} left-cap [false] Enable left cap style
52
- /// @prop {Color} left-cap-color ["link"] The color for the left cap
53
- /// @prop {color} left-cap-color-hover ["link-hover"] The color for the left cap when the button is hovered
54
- /// @prop {Number} left-cap-color-hover [0.5rem] Width of the cap
55
- /// @prop {Number} left-cap-match-radius [true] The cap should have be rounded to match the parent's border radius
51
+ /// @prop {Boolean} cap [false] Enable left cap style
52
+ /// @prop {Color} cap-side ["left"] The side that gets the cap
53
+ /// @prop {Number} cap-match-radius [true] The cap should have be rounded to match the parent's border radius
54
+ /// @prop {Map} cap-options The options for cap (see element.cap for options)
55
+ /// @prop {Map} cap-options-hover The options for cap when hovered
56
56
 
57
57
  $config: (
58
58
  "background-color" : white,
@@ -69,16 +69,21 @@ $config: (
69
69
  "margin" : 1em,
70
70
  "margin-inline" : 0.75em,
71
71
  "min-width": 20rem,
72
- "padding-x": 0.65em,
72
+ "padding-x": 0.75em,
73
73
  "padding-y": 1em,
74
74
  "title-color": "link",
75
75
  "title-margin" : 0.5em,
76
76
  "title-color-hover" : "link-hover",
77
- "left-cap" : false,
78
- "left-cap-color" : "link",
79
- "left-cap-color-hover" : "link-hover",
80
- "left-cap-width" : 0.5rem,
81
- "left-cap-match-radius" : true
77
+ "cap" : false,
78
+ "cap-side" : "left",
79
+ "cap-match-radius" : true,
80
+ "cap-options" : (
81
+ "color" : "link",
82
+ "size" : 0.5rem,
83
+ ),
84
+ "cap-options-hover" : (
85
+ "color" : "link-hover"
86
+ ),
82
87
  ) !default;
83
88
 
84
89
  /// Change modules $config
@@ -112,40 +117,30 @@ $config: (
112
117
 
113
118
  @mixin styles {
114
119
  $prefix: selector.class("button-verbose");
120
+ $padding-x: get("padding-x");
121
+ $padding-y: get("padding-y");
122
+ $padding-right: ($padding-x * 2) + 1em;
123
+ $cap-side: get("cap-side");
124
+ $cap-defaults: (
125
+ "border-radius" : if(get("cap-match-radius"), get("border-radius"), 0),
126
+ "padding-adjust" : if(utils.is-side($cap-side), $padding-x, $padding-y)
127
+ );
115
128
 
116
129
  #{ $prefix } {
117
130
  text-decoration: none;
118
131
  border-radius: get("border-radius");
119
132
  box-shadow: get("box-shadow");
120
133
  line-height: get("line-height");
121
- position: relative;
134
+ position: relative; // For cap and icon
122
135
  display: block;
123
136
  margin-bottom: get("margin");
124
137
  max-width: 100%;
125
138
  width: get("min-width");
126
139
  background-color: color.get(get("background-color"));
127
- padding: get("padding-y") get("padding-x");
128
- padding-right: (get("padding-x") * 2) + 1em;
140
+ padding: $padding-y $padding-right $padding-y $padding-x;
129
141
  color: color.get(get("color"));
130
142
  text-align: left;
131
- // Add border like cap
132
- @if get("left-cap") {
133
- padding-left: calc(get("padding-x") + get("left-cap-width"));
134
- &::after {
135
- content: "";
136
- display: block;
137
- position: absolute;
138
- top: 0;
139
- bottom: 0;
140
- left: 0;
141
- width: get("left-cap-width");
142
- background-color: color.get(get("left-cap-color"));
143
- @if get("left-cap-match-radius") {
144
- border-top-left-radius: get("border-radius");
145
- border-bottom-left-radius: get("border-radius");
146
- }
147
- }
148
- }
143
+
149
144
  &:hover {
150
145
  color: color.get(get("color-hover"));
151
146
  background-color: color.get(get("background-color-hover"));
@@ -160,9 +155,19 @@ $config: (
160
155
  color: color.get(get("icon-color-hover"));
161
156
  }
162
157
  }
163
- @if (get("left-cap") and get("left-cap-color-hover")) {
164
- &::after {
165
- background-color: color.get(get("left-cap-color-hover"));
158
+ }
159
+ @if get("cap") {
160
+ @include element.cap(
161
+ $side: $cap-side,
162
+ $options: map.merge($cap-defaults, get("cap-options"))
163
+ );
164
+ @if get("cap-options-hover") {
165
+ &:hover,
166
+ &:focus {
167
+ @include element.cap-appearance(
168
+ $side: $cap-side,
169
+ $options: get("cap-options-hover")
170
+ );
166
171
  }
167
172
  }
168
173
  }
@@ -180,7 +185,7 @@ $config: (
180
185
  #{ $prefix }__icon {
181
186
  position: absolute;
182
187
  top: 50%;
183
- right: get("padding-x");
188
+ right: $padding-x;
184
189
  transform: translateY(-50%);
185
190
  font-size: get("icon-font-size");
186
191
  color: color.get(get("icon-color"));