@leaflink/stash 41.6.4 → 42.0.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.
package/dist/AppTopbar.js CHANGED
@@ -1,4 +1,4 @@
1
- import { openBlock as n, createElementBlock as d, createStaticVNode as h, defineComponent as c, createElementVNode as t, normalizeClass as l, createVNode as a, unref as m, renderSlot as o } from "vue";
1
+ import { openBlock as d, createElementBlock as n, createStaticVNode as h, defineComponent as c, createElementVNode as t, normalizeClass as l, createVNode as a, unref as m, renderSlot as o } from "vue";
2
2
  import p from "./Icon.js";
3
3
  import "./Icon.vue_used_vue_type_style_index_0_lang.module-d2507af3.js";
4
4
  import "./uniqueId-847efe53.js";
@@ -13,8 +13,8 @@ const C = {
13
13
  }, f = /* @__PURE__ */ h('<g id="wordmark"><path d="M0.265137 0.248474H4.14784V23.8197H0.265137V0.248474Z"></path><path d="M22.5861 17.1265H10.4927C10.9258 19.2695 12.6034 20.358 14.915 20.358C16.623 20.358 18.2313 19.6982 19.1693 18.446L21.7486 20.3913C20.3082 22.6331 17.561 23.8197 14.7132 23.8197C10.0242 23.8197 6.47314 20.589 6.47314 15.7754C6.47314 10.8628 10.2251 7.76257 14.6803 7.76257C19.1693 7.76257 22.6866 10.8313 22.6866 15.6424C22.682 16.1386 22.6485 16.6341 22.5861 17.1265ZM18.8004 14.4558C18.5657 12.3461 16.9244 11.1262 14.747 11.1262C12.6363 11.1262 10.9621 12.1151 10.4927 14.4558H18.8004Z"></path><path d="M41.6276 8.09331V23.8197H37.7414V21.4133C36.67 23.0611 34.4589 23.8197 32.5448 23.8197C28.4247 23.8197 24.8364 20.6879 24.8364 15.7754C24.8364 10.8313 28.3875 7.76257 32.5084 7.76257C34.4848 7.76257 36.6657 8.52123 37.7336 10.1366V8.09076L41.6276 8.09331ZM37.6747 15.7421C37.6747 13.0382 35.3969 11.324 33.1528 11.324C30.7407 11.324 28.7642 13.1704 28.7642 15.7421C28.7642 18.3139 30.7407 20.2259 33.1528 20.2259C35.5311 20.2259 37.6747 18.446 37.6747 15.7421Z"></path><path d="M48.9973 7.07127V8.42322H52.4808V11.4919H48.9973V23.8197H45.1145V7.26904C45.1145 2.85092 47.2547 0.180267 51.6103 0.180267H53.4534L52.3812 3.74085C49.7335 3.74085 48.9635 5.19167 48.9973 7.07127Z"></path><path d="M56.1824 0.250153H60.0677V23.8197H56.1824V0.250153Z"></path><path d="M62.9927 2.98303C62.9927 1.63109 64.1654 0.642273 65.539 0.642273C66.946 0.642273 68.051 1.63109 68.051 2.98303C68.051 4.30173 66.946 5.32379 65.539 5.32379C64.1688 5.32379 62.9927 4.30173 62.9927 2.98303ZM63.5989 8.42321H67.485V23.8197H63.5989V8.42321Z"></path><path d="M85.9341 15.1829V23.8197H82.0491V15.5444C82.0491 13.1047 80.5411 11.8517 78.7991 11.8517C77.0231 11.8517 74.8151 12.8081 74.8151 15.7728V23.8172H70.9241V8.4232H74.8101V10.8628C75.6131 8.95 78.0591 8.09332 79.6671 8.09332C83.6901 8.09332 85.9341 10.6975 85.9341 15.1829Z"></path><path d="M99.0731 23.8197L92.9751 16.8299V23.8197H89.0901V0.248474H92.9751V13.3349L97.4641 8.42323H102.523L96.1581 15.1489L103.996 23.8197H99.0731Z"></path></g>', 1), V = [
14
14
  f
15
15
  ];
16
- function b(r, i) {
17
- return n(), d("svg", C, V);
16
+ function b(r, w) {
17
+ return d(), n("svg", C, V);
18
18
  }
19
19
  const H = { render: b }, u = {
20
20
  "data-test": "stash-app-topbar",
@@ -26,9 +26,9 @@ const H = { render: b }, u = {
26
26
  href: { default: "/" }
27
27
  },
28
28
  emits: ["toggle-sidebar"],
29
- setup(r, { emit: i }) {
29
+ setup(r, { emit: w }) {
30
30
  const s = r;
31
- return (e, w) => (n(), d("header", u, [
31
+ return (e, i) => (d(), n("header", u, [
32
32
  t("div", {
33
33
  class: l(["tw-fixed tw-top-0 tw-pl-3 tw-flex tw-items-center tw-h-topbar tw-w-sidebar xl:tw-text-white tw-transition-colors tw-duration-500", {
34
34
  "tw-text-white tw-z-[1001]": s.sidebarOpened,
@@ -37,7 +37,7 @@ const H = { render: b }, u = {
37
37
  }, [
38
38
  t("button", {
39
39
  class: "xl:tw-hidden",
40
- onClick: w[0] || (w[0] = (M) => i("toggle-sidebar"))
40
+ onClick: i[0] || (i[0] = (M) => w("toggle-sidebar"))
41
41
  }, [
42
42
  a(p, {
43
43
  name: "menu",
@@ -58,7 +58,7 @@ const H = { render: b }, u = {
58
58
  ], 8, x)
59
59
  ], 2),
60
60
  t("div", {
61
- class: l([[e.$attrs.class], "tw-fixed tw-top-0 tw-w-full tw-pr-3 tw-py-3 tw-z-page tw-shadow-high tw-flex tw-items-center tw-justify-between tw-flex-row-reverse tw-bg-white tw-h-topbar tw-pl-sidebar"])
61
+ class: l([[e.$attrs.class], "tw-fixed tw-top-0 tw-w-full tw-pr-3 tw-py-3 tw-z-page tw-shadow-md tw-flex tw-items-center tw-justify-between tw-flex-row-reverse tw-bg-white tw-h-topbar tw-pl-sidebar"])
62
62
  }, [
63
63
  t("div", _, [
64
64
  o(e.$slots, "actions"),
package/dist/Box.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as m } from "./Box.vue_vue_type_script_setup_true_lang-dd4c9bc9.js";
1
+ import { _ as m } from "./Box.vue_vue_type_script_setup_true_lang-69e5176b.js";
2
2
  import "vue";
3
3
  export {
4
4
  m as default
@@ -15,7 +15,7 @@ const u = /* @__PURE__ */ s({
15
15
  "tw-rounded": e.radius === "rounded",
16
16
  "tw-p-gutter": !e.disablePadding && !e.disableGutters,
17
17
  "tw-py-gutter": e.disableGutters,
18
- "tw-shadow-low": !e.disableElevation
18
+ "tw-shadow": !e.disableElevation
19
19
  }]),
20
20
  "data-test": "stash-box"
21
21
  }, [
@@ -26,4 +26,4 @@ const u = /* @__PURE__ */ s({
26
26
  export {
27
27
  u as _
28
28
  };
29
- //# sourceMappingURL=Box.vue_vue_type_script_setup_true_lang-dd4c9bc9.js.map
29
+ //# sourceMappingURL=Box.vue_vue_type_script_setup_true_lang-69e5176b.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Box.vue_vue_type_script_setup_true_lang-69e5176b.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,7 +2,7 @@ import { ref as x, computed as D, defineComponent as R, useSlots as W, inject as
2
2
  import Q from "./useMediaQuery.js";
3
3
  import { SCREEN_SIZES as U } from "./constants.js";
4
4
  import { t as n } from "./locale.js";
5
- import { _ as Z } from "./Box.vue_vue_type_script_setup_true_lang-dd4c9bc9.js";
5
+ import { _ as Z } from "./Box.vue_vue_type_script_setup_true_lang-69e5176b.js";
6
6
  import A from "./Button.js";
7
7
  import T from "./Icon.js";
8
8
  import "./Paginate.vue_used_vue_type_style_index_0_lang.module-e579235f.js";
package/dist/Dropdown.js CHANGED
@@ -1,10 +1,10 @@
1
- import { defineComponent as q, ref as u, useCssModule as z, watch as C, onMounted as I, onBeforeUnmount as K, computed as U, withDirectives as _, openBlock as v, createElementBlock as k, renderSlot as x, createElementVNode as E, normalizeClass as b, createTextVNode as V, toDisplayString as W, createVNode as S, createBlock as Y, Transition as F, withCtx as j, unref as M, normalizeStyle as G, vShow as H, nextTick as A } from "vue";
1
+ import { defineComponent as R, ref as u, useCssModule as z, watch as C, onMounted as I, onBeforeUnmount as q, computed as K, withDirectives as _, openBlock as p, createElementBlock as k, renderSlot as x, createElementVNode as E, normalizeClass as b, createTextVNode as U, toDisplayString as V, createVNode as S, createBlock as W, Transition as Y, withCtx as F, unref as M, normalizeStyle as j, vShow as G, nextTick as A } from "vue";
2
2
  import { KEY_CODES as d } from "./constants.js";
3
- import J from "./clickoutside.js";
4
- import Q from "./utils/calculateElementOverflow.js";
5
- import { getMountPoint as X } from "./utils/helpers.js";
3
+ import H from "./clickoutside.js";
4
+ import J from "./utils/calculateElementOverflow.js";
5
+ import { getMountPoint as Q } from "./utils/helpers.js";
6
6
  import B from "./Icon.js";
7
- import { _ as Z } from "./_plugin-vue_export-helper-dad06003.js";
7
+ import { _ as X } from "./_plugin-vue_export-helper-dad06003.js";
8
8
  import "./capitalize-667d9f60.js";
9
9
  import "./toString-7d5bf363.js";
10
10
  import "./isObjectLike-54341556.js";
@@ -17,10 +17,10 @@ import "./_overArg-6d920d99.js";
17
17
  import "./Icon.vue_used_vue_type_style_index_0_lang.module-d2507af3.js";
18
18
  import "./uniqueId-847efe53.js";
19
19
  import "./index-79ce320f.js";
20
- const ee = ["aria-expanded"], te = {
20
+ const Z = ["aria-expanded"], ee = {
21
21
  key: 0,
22
22
  class: "tw-font-medium tw-flex tw-items-center tw-text-blue hover:tw-text-blue-700"
23
- }, oe = /* @__PURE__ */ q({
23
+ }, te = /* @__PURE__ */ R({
24
24
  name: "ll-dropdown",
25
25
  __name: "Dropdown",
26
26
  props: {
@@ -33,105 +33,105 @@ const ee = ["aria-expanded"], te = {
33
33
  fluidContent: { type: Boolean, default: !1 }
34
34
  },
35
35
  emits: ["toggle", "dismiss"],
36
- setup(D, { expose: $, emit: m }) {
37
- const n = D, t = u(null), w = u(null), f = [], a = u(f), s = u(-1), o = u(!1), g = u({}), L = z();
36
+ setup(D, { expose: $, emit: v }) {
37
+ const a = D, t = u(null), w = u(null), f = [], s = u(f), i = u(-1), o = u(!1), g = u({}), L = z();
38
38
  C(o, (e) => {
39
- e || (s.value = -1), m("toggle", e);
40
- }), C(s, (e, l) => {
41
- e in a.value && a.value[e].classList.add("is-highlighted"), l in a.value && a.value[l].classList.remove("is-highlighted");
39
+ e || (i.value = -1), v("toggle", e);
40
+ }), C(i, (e, l) => {
41
+ e in s.value && s.value[e].classList.add("is-highlighted"), l in s.value && s.value[l].classList.remove("is-highlighted");
42
42
  }), I(() => {
43
- var e, l, r;
44
- if (n.reattach) {
45
- const c = X();
43
+ var e, l, n;
44
+ if (a.reattach) {
45
+ const c = Q();
46
46
  t.value && c.appendChild(t.value);
47
47
  }
48
- (e = t.value) != null && e.querySelector(".stash-menu") ? a.value = ((l = t.value) == null ? void 0 : l.querySelectorAll(".stash-menu-item")) ?? f : a.value = ((r = t.value) == null ? void 0 : r.querySelectorAll(".dropdown__item")) ?? f, window.addEventListener("resize", i);
49
- }), K(() => {
48
+ (e = t.value) != null && e.querySelector(".stash-menu") ? s.value = ((l = t.value) == null ? void 0 : l.querySelectorAll(".stash-menu-item")) ?? f : s.value = ((n = t.value) == null ? void 0 : n.querySelectorAll(".dropdown__item")) ?? f, window.addEventListener("resize", r);
49
+ }), q(() => {
50
50
  var e, l;
51
- window.removeEventListener("resize", i), (l = (e = t.value) == null ? void 0 : e.parentNode) == null || l.removeChild(t.value);
51
+ window.removeEventListener("resize", r), (l = (e = t.value) == null ? void 0 : e.parentNode) == null || l.removeChild(t.value);
52
52
  });
53
- function i() {
54
- const e = o.value;
55
- o.value = !1, e && m("dismiss");
53
+ function r(e) {
54
+ var n;
55
+ if (a.closeManually && ((n = t.value) != null && n.contains(e == null ? void 0 : e.target) || t.value === (e == null ? void 0 : e.target)))
56
+ return;
57
+ const l = o.value;
58
+ o.value = !1, l && v("dismiss");
56
59
  }
57
- async function p() {
60
+ async function m() {
58
61
  var e;
59
- o.value ? o.value = !1 : (o.value = !0, await P(), (e = t.value) == null || e.focus());
62
+ o.value ? o.value = !1 : (o.value = !0, await O(), (e = t.value) == null || e.focus());
60
63
  }
61
64
  function T(e) {
62
- n.closeManually && e.stopPropagation();
63
- }
64
- function N(e) {
65
65
  if (e.keyCode === d.ESCAPE)
66
- i();
67
- else if (e.keyCode === d.DOWN && s.value < a.value.length - 1)
68
- o.value && s.value++;
69
- else if (e.keyCode === d.UP && s.value > -1)
70
- o.value && s.value--;
71
- else if (e.keyCode === d.ENTER && s.value !== -1)
72
- o.value && a[s.value].click();
66
+ r();
67
+ else if (e.keyCode === d.DOWN && i.value < s.value.length - 1)
68
+ o.value && i.value++;
69
+ else if (e.keyCode === d.UP && i.value > -1)
70
+ o.value && i.value--;
71
+ else if (e.keyCode === d.ENTER && i.value !== -1)
72
+ o.value && s[i.value].click();
73
73
  else
74
74
  return;
75
75
  e.preventDefault();
76
76
  }
77
- function O() {
77
+ function N() {
78
78
  var e;
79
79
  (e = t.value) == null || e.style.setProperty("--offset", "0");
80
80
  }
81
- async function P() {
81
+ async function O() {
82
82
  var h, y;
83
83
  await A();
84
- const e = ((h = w.value) == null ? void 0 : h.getBoundingClientRect()) || {}, l = e.top + e.height, r = {
84
+ const e = ((h = w.value) == null ? void 0 : h.getBoundingClientRect()) || {}, l = e.top + e.height, n = {
85
85
  x: 0,
86
86
  y: 0,
87
- ...n.offset
87
+ ...a.offset
88
88
  };
89
- n.reattach && (g.value = {
90
- left: n.align === "left" ? `${Math.round(e.left) + r.x}px` : void 0,
91
- right: n.align === "right" ? `${document.documentElement.clientWidth - Math.round(e.right) + r.x}px` : void 0,
92
- top: `${window.scrollY + l + r.y}px`
89
+ a.reattach && (g.value = {
90
+ left: a.align === "left" ? `${Math.round(e.left) + n.x}px` : void 0,
91
+ right: a.align === "right" ? `${document.documentElement.clientWidth - Math.round(e.right) + n.x}px` : void 0,
92
+ top: `${window.scrollY + l + n.y}px`
93
93
  }, await A());
94
- const c = Q(t == null ? void 0 : t.value);
94
+ const c = J(t == null ? void 0 : t.value);
95
95
  if (c) {
96
- const R = n.align === "left" ? "-" : "";
97
- (y = t.value) == null || y.style.setProperty("--offset", `${R}${c.value}`);
96
+ const P = a.align === "left" ? "-" : "";
97
+ (y = t.value) == null || y.style.setProperty("--offset", `${P}${c.value}`);
98
98
  }
99
99
  }
100
100
  return $({
101
- isActive: U(() => o.value),
102
- toggle: p,
103
- dismiss: i
104
- }), (e, l) => _((v(), k("div", {
101
+ isActive: K(() => o.value),
102
+ toggle: m,
103
+ dismiss: r
104
+ }), (e, l) => _((p(), k("div", {
105
105
  ref_key: "dropdownRef",
106
106
  ref: w,
107
107
  class: "tw-inline-block tw-relative",
108
108
  "data-test": "ll-dropdown",
109
- onKeydown: N
109
+ onKeydown: T
110
110
  }, [
111
111
  x(e.$slots, "toggle", {
112
112
  isActive: o.value,
113
- toggle: p
113
+ toggle: m
114
114
  }, () => [
115
115
  E("button", {
116
116
  "data-test": "button|toggle",
117
117
  "aria-expanded": o.value,
118
118
  class: b([e.label ? "button--tertiary tw-outline-none tw-min-w-auto" : "button--icon button tw-rounded"]),
119
- onClick: p
119
+ onClick: m
120
120
  }, [
121
- e.label ? (v(), k("span", te, [
122
- V(W(e.label) + " ", 1),
121
+ e.label ? (p(), k("span", ee, [
122
+ U(V(e.label) + " ", 1),
123
123
  S(B, { name: "caret-down" })
124
- ])) : (v(), Y(B, {
124
+ ])) : (p(), W(B, {
125
125
  key: 1,
126
126
  name: "ellipsis"
127
127
  }))
128
- ], 10, ee)
128
+ ], 10, Z)
129
129
  ]),
130
- S(F, {
130
+ S(Y, {
131
131
  name: "fade",
132
- onAfterLeave: O
132
+ onAfterLeave: N
133
133
  }, {
134
- default: j(() => [
134
+ default: F(() => [
135
135
  _(E("div", {
136
136
  ref_key: "contentRef",
137
137
  ref: t,
@@ -140,34 +140,33 @@ const ee = ["aria-expanded"], te = {
140
140
  M(L).content,
141
141
  e.contentClass,
142
142
  {
143
- "tw-left-0 after:tw-left-6": n.align === "left",
144
- "tw-right-0": n.align === "right",
145
- "tw-max-w-[360px]": !n.fluidContent
143
+ "tw-left-0 after:tw-left-6": a.align === "left",
144
+ "tw-right-0": a.align === "right",
145
+ "tw-max-w-[360px]": !a.fluidContent
146
146
  }
147
147
  ]),
148
- style: G(g.value),
149
- onClick: T
148
+ style: j(g.value)
150
149
  }, [
151
150
  x(e.$slots, "default", {
152
- dismiss: i,
151
+ dismiss: r,
153
152
  isActive: o.value
154
153
  })
155
154
  ], 6), [
156
- [H, o.value]
155
+ [G, o.value]
157
156
  ])
158
157
  ]),
159
158
  _: 3
160
159
  })
161
160
  ], 32)), [
162
- [M(J), i]
161
+ [M(H), r]
163
162
  ]);
164
163
  }
165
- }), le = "_content_6dqhn_2", ne = {
166
- content: le
164
+ }), oe = "_content_naa5r_2", le = {
165
+ content: oe
167
166
  }, ae = {
168
- $style: ne
169
- }, be = /* @__PURE__ */ Z(oe, [["__cssModules", ae]]);
167
+ $style: le
168
+ }, Ee = /* @__PURE__ */ X(te, [["__cssModules", ae]]);
170
169
  export {
171
- be as default
170
+ Ee as default
172
171
  };
173
172
  //# sourceMappingURL=Dropdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.js","sources":["../src/components/Dropdown/Dropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, nextTick, onBeforeUnmount, onMounted, ref, useCssModule, watch } from 'vue';\n\n import { KEY_CODES } from '../../constants';\n import vClickoutside from '../../directives/clickoutside/clickoutside';\n import calculateElementOverflow from '../../utils/calculateElementOverflow';\n import { getMountPoint } from '../../utils/helpers';\n import Icon from '../Icon/Icon.vue';\n\n export type DropdownOffset = {\n x?: number;\n y?: number;\n };\n\n export interface DropdownProps {\n /**\n * Used to position the dropdown relative to target\n * Options: left, right\n */\n align?: 'left' | 'right';\n /**\n * When passed, text with caret is displayed instead of default kebab menu.\n */\n label?: string;\n /**\n * If true, dropdown will remain open when clicking on its content. Otherwise, it'll close automatically on click.\n */\n closeManually?: boolean;\n /**\n * Used to horizontally and vertically offset the dropdown in pixels\n * Keep in mind, `x` value is relative to `align` value.\n */\n offset?: DropdownOffset;\n /**\n * If `reattach` is true, the contents will be mounted in the mount point container,\n * so as to circumvent clipping issues from a parent's overflow property.\n */\n reattach?: boolean;\n /**\n * Custom class to apply to the default dropdown content element\n */\n contentClass?: string | string[];\n /**\n * Removes content container's max width\n */\n fluidContent?: boolean;\n }\n\n type DropdownStyles = {\n left?: string;\n right?: string;\n top?: string;\n };\n\n defineOptions({\n name: 'll-dropdown',\n });\n\n const props = withDefaults(defineProps<DropdownProps>(), {\n align: 'right',\n label: '',\n closeManually: false,\n offset: () => ({}),\n reattach: true,\n contentClass: '',\n fluidContent: false,\n });\n\n const emit =\n defineEmits<{\n toggle: [isActive: boolean];\n dismiss: [];\n }>();\n\n const contentRef = ref<HTMLElement | null>(null);\n const dropdownRef = ref<HTMLDivElement | null>(null);\n\n const DEFAULT_ITEMS_LIST = [] as unknown as NodeListOf<Element>;\n\n const items = ref<NodeListOf<Element>>(DEFAULT_ITEMS_LIST);\n const itemIndex = ref(-1);\n const isActive = ref(false);\n\n const styles = ref<DropdownStyles>({});\n const classes = useCssModule();\n\n watch(isActive, (val) => {\n if (!val) {\n itemIndex.value = -1;\n }\n\n emit('toggle', val);\n });\n\n watch(itemIndex, (next, prev) => {\n next in items.value && items.value[next].classList.add('is-highlighted');\n prev in items.value && items.value[prev].classList.remove('is-highlighted');\n });\n\n onMounted(() => {\n if (props.reattach) {\n const target = getMountPoint();\n\n contentRef.value && target.appendChild(contentRef.value);\n }\n\n // if stash-menu exists, use it's items\n if (contentRef.value?.querySelector('.stash-menu')) {\n items.value = contentRef.value?.querySelectorAll('.stash-menu-item') ?? DEFAULT_ITEMS_LIST;\n } else {\n items.value = contentRef.value?.querySelectorAll('.dropdown__item') ?? DEFAULT_ITEMS_LIST;\n }\n\n window.addEventListener('resize', dismiss);\n });\n\n onBeforeUnmount(() => {\n window.removeEventListener('resize', dismiss);\n contentRef.value?.parentNode?.removeChild(contentRef.value);\n });\n\n /**\n * Dismisses the Dropdown.\n */\n function dismiss() {\n const wasOpen = isActive.value;\n\n isActive.value = false;\n\n if (wasOpen) {\n emit('dismiss');\n }\n }\n\n /**\n * Opens or closes the Dropdown. If opening, positions and focuses its content.\n */\n async function toggle() {\n if (isActive.value) {\n isActive.value = false;\n } else {\n isActive.value = true;\n await calculateOffset();\n contentRef.value?.focus();\n }\n }\n\n /**\n * Prevent the dropdown from closing if a user interacts with a UI item\n * within the dropdown `content`. By default, the dropdown will close\n * after a user clicks something within.\n * @param {Event} e The click event.\n */\n function stop(e: Event) {\n props.closeManually && e.stopPropagation();\n }\n\n /**\n * Handles all user keyboard input on the Dropdown.\n * @param {KeyboardEvent} e The native keydown event.\n */\n function onKeyDown(e: KeyboardEvent) {\n if (e.keyCode === KEY_CODES.ESCAPE) {\n dismiss();\n } else if (e.keyCode === KEY_CODES.DOWN && itemIndex.value < items.value.length - 1) {\n isActive.value && itemIndex.value++;\n } else if (e.keyCode === KEY_CODES.UP && itemIndex.value > -1) {\n isActive.value && itemIndex.value--;\n } else if (e.keyCode === KEY_CODES.ENTER && itemIndex.value !== -1) {\n isActive.value && items[itemIndex.value].click();\n } else {\n return;\n }\n\n e.preventDefault(); // if keyDown did something / we didn't return\n }\n\n /**\n * Reset any page overflow offset\n */\n function resetOffset() {\n contentRef.value?.style.setProperty('--offset', '0');\n }\n\n /**\n * Calculate the position for the Dropdown content element,\n * relative to the viewport.\n * Repositions the dropdown content element (& arrow)\n * if it overflows the page (including gutter).\n */\n async function calculateOffset() {\n await nextTick();\n\n const toggleBCR = dropdownRef.value?.getBoundingClientRect() || ({} as DOMRect);\n const top = toggleBCR.top + toggleBCR.height;\n const offset = {\n x: 0,\n y: 0,\n ...props.offset,\n };\n\n if (props.reattach) {\n styles.value = {\n left: props.align === 'left' ? `${Math.round(toggleBCR.left) + offset.x}px` : undefined,\n right:\n props.align === 'right'\n ? `${document.documentElement.clientWidth - Math.round(toggleBCR.right) + offset.x}px`\n : undefined,\n top: `${window.scrollY + top + offset.y}px`,\n };\n await nextTick(); // wait for style updates to sync in the DOM\n }\n\n const overflow = calculateElementOverflow(contentRef?.value);\n\n if (overflow) {\n const direction = props.align === 'left' ? '-' : '';\n contentRef.value?.style.setProperty('--offset', `${direction}${overflow.value}`);\n }\n }\n\n defineExpose({\n isActive: computed(() => isActive.value),\n toggle,\n dismiss,\n });\n</script>\n\n<template>\n <div\n ref=\"dropdownRef\"\n v-clickoutside=\"dismiss\"\n class=\"tw-inline-block tw-relative\"\n data-test=\"ll-dropdown\"\n @keydown=\"onKeyDown\"\n >\n <!-- @slot Toggle component slot, receives `toggle` method to trigger Dropdown display -->\n <slot name=\"toggle\" :is-active=\"isActive\" :toggle=\"toggle\">\n <button\n data-test=\"button|toggle\"\n :aria-expanded=\"isActive\"\n :class=\"[label ? 'button--tertiary tw-outline-none tw-min-w-auto' : 'button--icon button tw-rounded']\"\n @click=\"toggle\"\n >\n <span v-if=\"label\" class=\"tw-font-medium tw-flex tw-items-center tw-text-blue hover:tw-text-blue-700\">\n {{ label }}\n <Icon name=\"caret-down\" />\n </span>\n <Icon v-else name=\"ellipsis\" />\n </button>\n </slot>\n\n <transition name=\"fade\" @after-leave=\"resetOffset\">\n <div\n v-show=\"isActive\"\n ref=\"contentRef\"\n data-test=\"ll-dropdown-content\"\n :class=\"[\n classes.content,\n contentClass,\n {\n 'tw-left-0 after:tw-left-6': props.align === 'left',\n 'tw-right-0': props.align === 'right',\n 'tw-max-w-[360px]': !props.fluidContent,\n },\n ]\"\n :style=\"styles\"\n @click=\"stop\"\n >\n <!-- @slot Dropdown content slot. Receives `dismiss` method, to trigger manual close. Receives `is-active` prop. -->\n <slot :dismiss=\"dismiss\" :is-active=\"isActive\"></slot>\n </div>\n </transition>\n </div>\n</template>\n\n<style module>\n .content {\n --offset: 0;\n\n @apply tw-shadow-low\n tw-bg-white\n tw-border\n tw-border-solid\n tw-border-blue\n tw-rounded\n tw-absolute\n tw-z-control\n tw-min-w-[200px];\n\n transform: translateX(calc(var(--offset) * 1px));\n }\n\n /**\n * TODO: these global styles should be componentized in https://leaflink.atlassian.net/browse/STASH-566\n */\n :global(.dropdown__list) {\n @apply tw-bg-white tw-list-none tw-m-1.5 tw-p-0;\n }\n\n :global(.dropdown__item) {\n @apply tw-block tw-mx-0 tw-mt-0 tw-mb-1.5 tw-w-full first:tw-mt-0 last:tw-mb-0;\n }\n\n :global(.dropdown__item) button {\n @apply tw-border-none tw-text-left tw-p-1.5;\n }\n\n :global(.dropdown__item) :where(a, button) {\n @apply tw-rounded\n tw-text-ice-700\n tw-block\n tw-py-[10px]\n tw-px-1.5\n tw-w-full\n disabled:tw-text-ice\n disabled:tw-cursor-default\n hover:tw-bg-ice-200\n hover:tw-text-ice-700\n hover:tw-no-underline\n tw-transition-all\n tw-duration-fast\n tw-ease-swing;\n }\n</style>\n"],"names":["contentRef","ref","dropdownRef","DEFAULT_ITEMS_LIST","items","itemIndex","isActive","styles","classes","useCssModule","watch","val","emit","next","prev","onMounted","props","target","getMountPoint","_a","_b","_c","dismiss","onBeforeUnmount","wasOpen","toggle","calculateOffset","stop","onKeyDown","KEY_CODES","resetOffset","nextTick","toggleBCR","top","offset","overflow","calculateElementOverflow","direction","__expose","computed"],"mappings":"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"}
1
+ {"version":3,"file":"Dropdown.js","sources":["../src/components/Dropdown/Dropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, nextTick, onBeforeUnmount, onMounted, ref, useCssModule, watch } from 'vue';\n\n import { KEY_CODES } from '../../constants';\n import vClickoutside from '../../directives/clickoutside/clickoutside';\n import calculateElementOverflow from '../../utils/calculateElementOverflow';\n import { getMountPoint } from '../../utils/helpers';\n import Icon from '../Icon/Icon.vue';\n\n export type DropdownOffset = {\n x?: number;\n y?: number;\n };\n\n export interface DropdownProps {\n /**\n * Used to position the dropdown relative to target\n * Options: left, right\n */\n align?: 'left' | 'right';\n /**\n * When passed, text with caret is displayed instead of default kebab menu.\n */\n label?: string;\n /**\n * If true, dropdown will remain open when clicking on its content. Otherwise, it'll close automatically on click.\n */\n closeManually?: boolean;\n /**\n * Used to horizontally and vertically offset the dropdown in pixels\n * Keep in mind, `x` value is relative to `align` value.\n */\n offset?: DropdownOffset;\n /**\n * If `reattach` is true, the contents will be mounted in the mount point container,\n * so as to circumvent clipping issues from a parent's overflow property.\n */\n reattach?: boolean;\n /**\n * Custom class to apply to the default dropdown content element\n */\n contentClass?: string | string[];\n /**\n * Removes content container's max width\n */\n fluidContent?: boolean;\n }\n\n type DropdownStyles = {\n left?: string;\n right?: string;\n top?: string;\n };\n\n defineOptions({\n name: 'll-dropdown',\n });\n\n const props = withDefaults(defineProps<DropdownProps>(), {\n align: 'right',\n label: '',\n closeManually: false,\n offset: () => ({}),\n reattach: true,\n contentClass: '',\n fluidContent: false,\n });\n\n const emit =\n defineEmits<{\n toggle: [isActive: boolean];\n dismiss: [];\n }>();\n\n const contentRef = ref<HTMLElement | null>(null);\n const dropdownRef = ref<HTMLDivElement | null>(null);\n\n const DEFAULT_ITEMS_LIST = [] as unknown as NodeListOf<Element>;\n\n const items = ref<NodeListOf<Element>>(DEFAULT_ITEMS_LIST);\n const itemIndex = ref(-1);\n const isActive = ref(false);\n\n const styles = ref<DropdownStyles>({});\n const classes = useCssModule();\n\n watch(isActive, (val) => {\n if (!val) {\n itemIndex.value = -1;\n }\n\n emit('toggle', val);\n });\n\n watch(itemIndex, (next, prev) => {\n next in items.value && items.value[next].classList.add('is-highlighted');\n prev in items.value && items.value[prev].classList.remove('is-highlighted');\n });\n\n onMounted(() => {\n if (props.reattach) {\n const target = getMountPoint();\n\n contentRef.value && target.appendChild(contentRef.value);\n }\n\n // if stash-menu exists, use it's items\n if (contentRef.value?.querySelector('.stash-menu')) {\n items.value = contentRef.value?.querySelectorAll('.stash-menu-item') ?? DEFAULT_ITEMS_LIST;\n } else {\n items.value = contentRef.value?.querySelectorAll('.dropdown__item') ?? DEFAULT_ITEMS_LIST;\n }\n\n window.addEventListener('resize', dismiss);\n });\n\n onBeforeUnmount(() => {\n window.removeEventListener('resize', dismiss);\n contentRef.value?.parentNode?.removeChild(contentRef.value);\n });\n\n /**\n * Dismisses the Dropdown.\n */\n function dismiss(event?: Event) {\n if (\n props.closeManually &&\n (contentRef.value?.contains(event?.target as HTMLElement) || contentRef.value === event?.target)\n ) {\n return;\n }\n\n const wasOpen = isActive.value;\n\n isActive.value = false;\n\n if (wasOpen) {\n emit('dismiss');\n }\n }\n\n /**\n * Opens or closes the Dropdown. If opening, positions and focuses its content.\n */\n async function toggle() {\n if (isActive.value) {\n isActive.value = false;\n } else {\n isActive.value = true;\n await calculateOffset();\n contentRef.value?.focus();\n }\n }\n\n /**\n * Handles all user keyboard input on the Dropdown.\n * @param {KeyboardEvent} e The native keydown event.\n */\n function onKeyDown(e: KeyboardEvent) {\n if (e.keyCode === KEY_CODES.ESCAPE) {\n dismiss();\n } else if (e.keyCode === KEY_CODES.DOWN && itemIndex.value < items.value.length - 1) {\n isActive.value && itemIndex.value++;\n } else if (e.keyCode === KEY_CODES.UP && itemIndex.value > -1) {\n isActive.value && itemIndex.value--;\n } else if (e.keyCode === KEY_CODES.ENTER && itemIndex.value !== -1) {\n isActive.value && items[itemIndex.value].click();\n } else {\n return;\n }\n\n e.preventDefault(); // if keyDown did something / we didn't return\n }\n\n /**\n * Reset any page overflow offset\n */\n function resetOffset() {\n contentRef.value?.style.setProperty('--offset', '0');\n }\n\n /**\n * Calculate the position for the Dropdown content element,\n * relative to the viewport.\n * Repositions the dropdown content element (& arrow)\n * if it overflows the page (including gutter).\n */\n async function calculateOffset() {\n await nextTick();\n\n const toggleBCR = dropdownRef.value?.getBoundingClientRect() || ({} as DOMRect);\n const top = toggleBCR.top + toggleBCR.height;\n const offset = {\n x: 0,\n y: 0,\n ...props.offset,\n };\n\n if (props.reattach) {\n styles.value = {\n left: props.align === 'left' ? `${Math.round(toggleBCR.left) + offset.x}px` : undefined,\n right:\n props.align === 'right'\n ? `${document.documentElement.clientWidth - Math.round(toggleBCR.right) + offset.x}px`\n : undefined,\n top: `${window.scrollY + top + offset.y}px`,\n };\n await nextTick(); // wait for style updates to sync in the DOM\n }\n\n const overflow = calculateElementOverflow(contentRef?.value);\n\n if (overflow) {\n const direction = props.align === 'left' ? '-' : '';\n contentRef.value?.style.setProperty('--offset', `${direction}${overflow.value}`);\n }\n }\n\n defineExpose({\n isActive: computed(() => isActive.value),\n toggle,\n dismiss,\n });\n</script>\n\n<template>\n <div\n ref=\"dropdownRef\"\n v-clickoutside=\"dismiss\"\n class=\"tw-inline-block tw-relative\"\n data-test=\"ll-dropdown\"\n @keydown=\"onKeyDown\"\n >\n <!-- @slot Toggle component slot, receives `toggle` method to trigger Dropdown display -->\n <slot name=\"toggle\" :is-active=\"isActive\" :toggle=\"toggle\">\n <button\n data-test=\"button|toggle\"\n :aria-expanded=\"isActive\"\n :class=\"[label ? 'button--tertiary tw-outline-none tw-min-w-auto' : 'button--icon button tw-rounded']\"\n @click=\"toggle\"\n >\n <span v-if=\"label\" class=\"tw-font-medium tw-flex tw-items-center tw-text-blue hover:tw-text-blue-700\">\n {{ label }}\n <Icon name=\"caret-down\" />\n </span>\n <Icon v-else name=\"ellipsis\" />\n </button>\n </slot>\n\n <transition name=\"fade\" @after-leave=\"resetOffset\">\n <div\n v-show=\"isActive\"\n ref=\"contentRef\"\n data-test=\"ll-dropdown-content\"\n :class=\"[\n classes.content,\n contentClass,\n {\n 'tw-left-0 after:tw-left-6': props.align === 'left',\n 'tw-right-0': props.align === 'right',\n 'tw-max-w-[360px]': !props.fluidContent,\n },\n ]\"\n :style=\"styles\"\n >\n <!-- @slot Dropdown content slot. Receives `dismiss` method, to trigger manual close. You must call dismiss with parentheses. Receives `is-active` prop. -->\n <slot :dismiss=\"dismiss\" :is-active=\"isActive\"></slot>\n </div>\n </transition>\n </div>\n</template>\n\n<style module>\n .content {\n --offset: 0;\n\n @apply tw-shadow\n tw-bg-white\n tw-border\n tw-border-solid\n tw-border-blue\n tw-rounded\n tw-absolute\n tw-z-control\n tw-min-w-[200px];\n\n transform: translateX(calc(var(--offset) * 1px));\n }\n\n /**\n * TODO: these global styles should be componentized in https://leaflink.atlassian.net/browse/STASH-566\n */\n :global(.dropdown__list) {\n @apply tw-bg-white tw-list-none tw-m-1.5 tw-p-0;\n }\n\n :global(.dropdown__item) {\n @apply tw-block tw-mx-0 tw-mt-0 tw-mb-1.5 tw-w-full first:tw-mt-0 last:tw-mb-0;\n }\n\n :global(.dropdown__item) button {\n @apply tw-border-none tw-text-left tw-p-1.5;\n }\n\n :global(.dropdown__item) :where(a, button) {\n @apply tw-rounded\n tw-text-ice-700\n tw-block\n tw-py-[10px]\n tw-px-1.5\n tw-w-full\n disabled:tw-text-ice\n disabled:tw-cursor-default\n hover:tw-bg-ice-200\n hover:tw-text-ice-700\n hover:tw-no-underline\n tw-transition-all\n tw-duration-fast\n tw-ease-swing;\n }\n</style>\n"],"names":["contentRef","ref","dropdownRef","DEFAULT_ITEMS_LIST","items","itemIndex","isActive","styles","classes","useCssModule","watch","val","emit","next","prev","onMounted","props","target","getMountPoint","_a","_b","_c","dismiss","onBeforeUnmount","event","wasOpen","toggle","calculateOffset","onKeyDown","KEY_CODES","resetOffset","nextTick","toggleBCR","top","offset","overflow","calculateElementOverflow","direction","__expose","computed"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0EQA,IAAaC,EAAwB,IAAI,GACzCC,IAAcD,EAA2B,IAAI,GAE7CE,IAAqB,CAAA,GAErBC,IAAQH,EAAyBE,CAAkB,GACnDE,IAAYJ,EAAI,EAAE,GAClBK,IAAWL,EAAI,EAAK,GAEpBM,IAASN,EAAoB,CAAA,CAAE,GAC/BO,IAAUC;AAEV,IAAAC,EAAAJ,GAAU,CAACK,MAAQ;AACvB,MAAKA,MACHN,EAAU,QAAQ,KAGpBO,EAAK,UAAUD,CAAG;AAAA,IAAA,CACnB,GAEKD,EAAAL,GAAW,CAACQ,GAAMC,MAAS;AACvB,MAAAD,KAAAT,EAAM,SAASA,EAAM,MAAMS,CAAI,EAAE,UAAU,IAAI,gBAAgB,GAC/DC,KAAAV,EAAM,SAASA,EAAM,MAAMU,CAAI,EAAE,UAAU,OAAO,gBAAgB;AAAA,IAAA,CAC3E,GAEDC,EAAU,MAAM;;AACd,UAAIC,EAAM,UAAU;AAClB,cAAMC,IAASC;AAEf,QAAAlB,EAAW,SAASiB,EAAO,YAAYjB,EAAW,KAAK;AAAA,MACzD;AAGA,OAAImB,IAAAnB,EAAW,UAAX,QAAAmB,EAAkB,cAAc,iBAClCf,EAAM,UAAQgB,IAAApB,EAAW,UAAX,gBAAAoB,EAAkB,iBAAiB,wBAAuBjB,IAExEC,EAAM,UAAQiB,IAAArB,EAAW,UAAX,gBAAAqB,EAAkB,iBAAiB,uBAAsBlB,GAGlE,OAAA,iBAAiB,UAAUmB,CAAO;AAAA,IAAA,CAC1C,GAEDC,EAAgB,MAAM;;AACb,aAAA,oBAAoB,UAAUD,CAAO,IAC5CF,KAAAD,IAAAnB,EAAW,UAAX,gBAAAmB,EAAkB,eAAlB,QAAAC,EAA8B,YAAYpB,EAAW;AAAA,IAAK,CAC3D;AAKD,aAASsB,EAAQE,GAAe;;AAE5B,UAAAR,EAAM,mBACLG,IAAAnB,EAAW,UAAX,QAAAmB,EAAkB,SAASK,KAAA,gBAAAA,EAAO,WAA0BxB,EAAW,WAAUwB,KAAA,gBAAAA,EAAO;AAEzF;AAGF,YAAMC,IAAUnB,EAAS;AAEzB,MAAAA,EAAS,QAAQ,IAEbmB,KACFb,EAAK,SAAS;AAAA,IAElB;AAKA,mBAAec,IAAS;;AACtB,MAAIpB,EAAS,QACXA,EAAS,QAAQ,MAEjBA,EAAS,QAAQ,IACjB,MAAMqB,EAAgB,IACtBR,IAAAnB,EAAW,UAAX,QAAAmB,EAAkB;AAAA,IAEtB;AAMA,aAASS,EAAU,GAAkB;AAC/B,UAAA,EAAE,YAAYC,EAAU;AAClB,QAAAP;eACC,EAAE,YAAYO,EAAU,QAAQxB,EAAU,QAAQD,EAAM,MAAM,SAAS;AAChF,QAAAE,EAAS,SAASD,EAAU;AAAA,eACnB,EAAE,YAAYwB,EAAU,MAAMxB,EAAU,QAAQ;AACzD,QAAAC,EAAS,SAASD,EAAU;AAAA,eACnB,EAAE,YAAYwB,EAAU,SAASxB,EAAU,UAAU;AAC9D,QAAAC,EAAS,SAASF,EAAMC,EAAU,KAAK,EAAE;;AAEzC;AAGF,QAAE,eAAe;AAAA,IACnB;AAKA,aAASyB,IAAc;;AACrB,OAAAX,IAAAnB,EAAW,UAAX,QAAAmB,EAAkB,MAAM,YAAY,YAAY;AAAA,IAClD;AAQA,mBAAeQ,IAAkB;;AAC/B,YAAMI,EAAS;AAEf,YAAMC,MAAYb,IAAAjB,EAAY,UAAZ,gBAAAiB,EAAmB,4BAA4B,CAAA,GAC3Dc,IAAMD,EAAU,MAAMA,EAAU,QAChCE,IAAS;AAAA,QACb,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAGlB,EAAM;AAAA,MAAA;AAGX,MAAIA,EAAM,aACRT,EAAO,QAAQ;AAAA,QACb,MAAMS,EAAM,UAAU,SAAS,GAAG,KAAK,MAAMgB,EAAU,IAAI,IAAIE,EAAO,CAAC,OAAO;AAAA,QAC9E,OACElB,EAAM,UAAU,UACZ,GAAG,SAAS,gBAAgB,cAAc,KAAK,MAAMgB,EAAU,KAAK,IAAIE,EAAO,CAAC,OAChF;AAAA,QACN,KAAK,GAAG,OAAO,UAAUD,IAAMC,EAAO,CAAC;AAAA,MAAA,GAEzC,MAAMH,EAAS;AAGX,YAAAI,IAAWC,EAAyBpC,KAAA,gBAAAA,EAAY,KAAK;AAE3D,UAAImC,GAAU;AACZ,cAAME,IAAYrB,EAAM,UAAU,SAAS,MAAM;AACtC,SAAAI,IAAApB,EAAA,UAAA,QAAAoB,EAAO,MAAM,YAAY,YAAY,GAAGiB,CAAS,GAAGF,EAAS,KAAK;AAAA,MAC/E;AAAA,IACF;AAEa,WAAAG,EAAA;AAAA,MACX,UAAUC,EAAS,MAAMjC,EAAS,KAAK;AAAA,MACvC,QAAAoB;AAAA,MACA,SAAAJ;AAAA,IAAA,CACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -83,7 +83,7 @@ export default _default;
83
83
  /**
84
84
  * Dismisses the Dropdown.
85
85
  */
86
- declare function dismiss(): void;
86
+ declare function dismiss(event?: Event): void;
87
87
 
88
88
  export declare type DropdownOffset = {
89
89
  x?: number;
package/dist/Metric.js CHANGED
@@ -1,10 +1,10 @@
1
- import { defineComponent as w, useSlots as b, useCssModule as v, computed as r, openBlock as d, createElementBlock as i, normalizeClass as c, unref as t, createElementVNode as u, toDisplayString as m, renderSlot as y, createCommentVNode as x } from "vue";
1
+ import { defineComponent as b, useSlots as v, useCssModule as w, computed as r, openBlock as d, createElementBlock as i, normalizeClass as c, unref as t, createElementVNode as u, toDisplayString as m, renderSlot as y, createCommentVNode as x } from "vue";
2
2
  import { u as S } from "./uniqueId-847efe53.js";
3
3
  import { _ as h } from "./_plugin-vue_export-helper-dad06003.js";
4
4
  import "./toString-7d5bf363.js";
5
5
  import "./isObjectLike-54341556.js";
6
6
  var s = /* @__PURE__ */ ((e) => (e.Small = "small", e.Standard = "standard", e))(s || {}), _ = /* @__PURE__ */ ((e) => (e.Accent = "accent", e.Naked = "naked", e))(_ || {});
7
- const z = ["id"], k = ["aria-labelledby"], C = /* @__PURE__ */ w({
7
+ const z = ["id"], k = ["aria-labelledby"], C = /* @__PURE__ */ b({
8
8
  __name: "Metric",
9
9
  props: {
10
10
  value: { default: "" },
@@ -14,12 +14,12 @@ const z = ["id"], k = ["aria-labelledby"], C = /* @__PURE__ */ w({
14
14
  accentColor: { default: "teal" }
15
15
  },
16
16
  setup(e) {
17
- const a = e, p = b(), l = v(), o = r(() => S("metric-")), f = r(() => String(a.value));
17
+ const a = e, p = v(), l = w(), o = r(() => S("metric-")), f = r(() => String(a.value));
18
18
  return (n, B) => (d(), i("div", {
19
19
  class: c(["stash-metric", [
20
20
  `size--${a.size}`,
21
21
  {
22
- [`${t(l).accent} stash-metric--accent tw-p-3 tw-shadow-low tw-rounded tw-border-l-12 tw-border-${n.accentColor}`]: a.variant === t(_).Accent
22
+ [`${t(l).accent} stash-metric--accent tw-p-3 tw-shadow tw-rounded tw-border-l-12 tw-border-${n.accentColor}`]: a.variant === t(_).Accent
23
23
  }
24
24
  ]]),
25
25
  "data-test": "stash-metric"
@@ -1 +1 @@
1
- {"version":3,"file":"Metric.js","sources":["../src/components/Metric/Metric.types.ts","../src/components/Metric/Metric.vue"],"sourcesContent":["export enum Sizes {\n Small = 'small',\n Standard = 'standard',\n}\n\nexport type Size = `${Sizes}`;\n\nexport enum Variants {\n Accent = 'accent',\n Naked = 'naked',\n}\n\nexport type Variant = `${Variants}`;\n","<script lang=\"ts\">\n export * from './Metric.types';\n</script>\n\n<script setup lang=\"ts\">\n import uniqueId from 'lodash-es/uniqueId';\n import { computed, ComputedRef, useCssModule, useSlots } from 'vue';\n\n import { StashColor } from '../../../types/colors';\n import { Size, Sizes, Variant, Variants } from './Metric.types';\n\n export interface MetricProps {\n value: number | string;\n label: string;\n size?: Size;\n variant?: Variant;\n /**\n * Currently only used when the variant is `accent`\n */\n accentColor?: StashColor;\n }\n\n const props = withDefaults(defineProps<MetricProps>(), {\n size: 'standard',\n value: '',\n variant: 'naked',\n accentColor: 'teal',\n });\n\n const slots = useSlots();\n const classes = useCssModule();\n\n const fieldId = computed(() => uniqueId('metric-'));\n\n const computedValue: ComputedRef<string> = computed(() => String(props.value));\n</script>\n\n<template>\n <div\n class=\"stash-metric\"\n data-test=\"stash-metric\"\n :class=\"[\n `size--${props.size}`,\n {\n [`${classes.accent} stash-metric--accent tw-p-3 tw-shadow-low tw-rounded tw-border-l-12 tw-border-${accentColor}`]:\n props.variant === Variants.Accent,\n },\n ]\"\n >\n <div\n :id=\"fieldId\"\n class=\"tw-text-ice-700\"\n :class=\"[\n classes.label,\n { 'tw-text-xs': props.size === Sizes.Small },\n { 'tw-text-sm': props.size === Sizes.Standard },\n ]\"\n >\n {{ props.label }}\n </div>\n\n <div\n :aria-labelledby=\"fieldId\"\n class=\"tw-text-ice-900 tw-font-medium\"\n :class=\"[{ 'tw-text-base': props.size === Sizes.Small }, { 'tw-text-2xl': props.size === Sizes.Standard }]\"\n >\n {{ computedValue }}\n </div>\n\n <div v-if=\"slots.secondary\" class=\"text-ice-700 text-xs\" :class=\"classes.secondary\" data-test=\"secondary\">\n <slot name=\"secondary\"></slot>\n </div>\n </div>\n</template>\n\n<style module>\n .label {\n margin-bottom: 0.25rem; /* 4px */\n }\n\n .secondary {\n margin-top: 0.25rem; /* 4px */\n }\n\n /* bg-white also sets the border color, which causes conflicts in the payments app */\n .accent {\n background-color: white;\n }\n</style>\n"],"names":["Sizes","Variants","slots","useSlots","classes","useCssModule","fieldId","computed","uniqueId","computedValue","props"],"mappings":";;;;;AAAY,IAAAA,sBAAAA,OACVA,EAAA,QAAQ,SACRA,EAAA,WAAW,YAFDA,IAAAA,KAAA,CAAA,CAAA,GAOAC,sBAAAA,OACVA,EAAA,SAAS,UACTA,EAAA,QAAQ,SAFEA,IAAAA,KAAA,CAAA,CAAA;;;;;;;;;;;iBCsBJC,IAAQC,KACRC,IAAUC,KAEVC,IAAUC,EAAS,MAAMC,EAAS,SAAS,CAAC,GAE5CC,IAAqCF,EAAS,MAAM,OAAOG,EAAM,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"Metric.js","sources":["../src/components/Metric/Metric.types.ts","../src/components/Metric/Metric.vue"],"sourcesContent":["export enum Sizes {\n Small = 'small',\n Standard = 'standard',\n}\n\nexport type Size = `${Sizes}`;\n\nexport enum Variants {\n Accent = 'accent',\n Naked = 'naked',\n}\n\nexport type Variant = `${Variants}`;\n","<script lang=\"ts\">\n export * from './Metric.types';\n</script>\n\n<script setup lang=\"ts\">\n import uniqueId from 'lodash-es/uniqueId';\n import { computed, ComputedRef, useCssModule, useSlots } from 'vue';\n\n import { StashColor } from '../../../types/colors';\n import { Size, Sizes, Variant, Variants } from './Metric.types';\n\n export interface MetricProps {\n value: number | string;\n label: string;\n size?: Size;\n variant?: Variant;\n /**\n * Currently only used when the variant is `accent`\n */\n accentColor?: StashColor;\n }\n\n const props = withDefaults(defineProps<MetricProps>(), {\n size: 'standard',\n value: '',\n variant: 'naked',\n accentColor: 'teal',\n });\n\n const slots = useSlots();\n const classes = useCssModule();\n\n const fieldId = computed(() => uniqueId('metric-'));\n\n const computedValue: ComputedRef<string> = computed(() => String(props.value));\n</script>\n\n<template>\n <div\n class=\"stash-metric\"\n data-test=\"stash-metric\"\n :class=\"[\n `size--${props.size}`,\n {\n [`${classes.accent} stash-metric--accent tw-p-3 tw-shadow tw-rounded tw-border-l-12 tw-border-${accentColor}`]:\n props.variant === Variants.Accent,\n },\n ]\"\n >\n <div\n :id=\"fieldId\"\n class=\"tw-text-ice-700\"\n :class=\"[\n classes.label,\n { 'tw-text-xs': props.size === Sizes.Small },\n { 'tw-text-sm': props.size === Sizes.Standard },\n ]\"\n >\n {{ props.label }}\n </div>\n\n <div\n :aria-labelledby=\"fieldId\"\n class=\"tw-text-ice-900 tw-font-medium\"\n :class=\"[{ 'tw-text-base': props.size === Sizes.Small }, { 'tw-text-2xl': props.size === Sizes.Standard }]\"\n >\n {{ computedValue }}\n </div>\n\n <div v-if=\"slots.secondary\" class=\"text-ice-700 text-xs\" :class=\"classes.secondary\" data-test=\"secondary\">\n <slot name=\"secondary\"></slot>\n </div>\n </div>\n</template>\n\n<style module>\n .label {\n margin-bottom: 0.25rem; /* 4px */\n }\n\n .secondary {\n margin-top: 0.25rem; /* 4px */\n }\n\n /* bg-white also sets the border color, which causes conflicts in the payments app */\n .accent {\n background-color: white;\n }\n</style>\n"],"names":["Sizes","Variants","slots","useSlots","classes","useCssModule","fieldId","computed","uniqueId","computedValue","props"],"mappings":";;;;;AAAY,IAAAA,sBAAAA,OACVA,EAAA,QAAQ,SACRA,EAAA,WAAW,YAFDA,IAAAA,KAAA,CAAA,CAAA,GAOAC,sBAAAA,OACVA,EAAA,SAAS,UACTA,EAAA,QAAQ,SAFEA,IAAAA,KAAA,CAAA,CAAA;;;;;;;;;;;iBCsBJC,IAAQC,KACRC,IAAUC,KAEVC,IAAUC,EAAS,MAAMC,EAAS,SAAS,CAAC,GAE5CC,IAAqCF,EAAS,MAAM,OAAOG,EAAM,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/Modal.js CHANGED
@@ -1,4 +1,4 @@
1
- import { defineComponent as H, useSlots as I, ref as d, computed as x, watch as $, onBeforeUnmount as K, openBlock as a, createElementBlock as w, normalizeClass as s, withKeys as R, createVNode as C, withModifiers as j, createElementVNode as g, unref as f, renderSlot as m, toDisplayString as T, createCommentVNode as i, createBlock as F, withCtx as L } from "vue";
1
+ import { defineComponent as H, useSlots as I, ref as d, computed as x, watch as $, onBeforeUnmount as K, openBlock as a, createElementBlock as f, normalizeClass as s, withKeys as R, createVNode as C, withModifiers as j, createElementVNode as g, unref as w, renderSlot as m, toDisplayString as T, createCommentVNode as i, createBlock as F, withCtx as L } from "vue";
2
2
  import { u as V } from "./uniqueId-847efe53.js";
3
3
  import { FOCUS_ELEMENTS_SELECTOR as A } from "./constants.js";
4
4
  import { t as M } from "./locale.js";
@@ -68,7 +68,7 @@ const G = ["onKeydown"], J = ["aria-labelledby"], Q = { class: "tw-flex tw-place
68
68
  var c, S;
69
69
  t.key === "Tab" && (t.shiftKey && document.activeElement === b.value ? ((c = k.value) == null || c.focus(), t.preventDefault()) : document.activeElement === k.value && ((S = b.value) == null || S.focus(), t.preventDefault()));
70
70
  }
71
- return (t, c) => l.value ? (a(), w("div", {
71
+ return (t, c) => l.value ? (a(), f("div", {
72
72
  key: 0,
73
73
  ref_key: "rootRef",
74
74
  ref: r,
@@ -88,8 +88,8 @@ const G = ["onKeydown"], J = ["aria-labelledby"], Q = { class: "tw-flex tw-place
88
88
  g("div", {
89
89
  "aria-modal": "true",
90
90
  role: "dialog",
91
- "aria-labelledby": f(B),
92
- class: s(["stash-modal__dialog tw-flex tw-flex-col tw-h-screen tw-w-full lg:tw-shadow-low tw-relative", [
91
+ "aria-labelledby": w(B),
92
+ class: s(["stash-modal__dialog tw-flex tw-flex-col tw-h-screen tw-w-full lg:tw-shadow tw-relative", [
93
93
  `stash-modal__dialog--size-${e.size}`,
94
94
  `stash-modal__dialog--position-${e.position}`,
95
95
  {
@@ -109,7 +109,7 @@ const G = ["onKeydown"], J = ["aria-labelledby"], Q = { class: "tw-flex tw-place
109
109
  onClick: c[0] || (c[0] = j(() => {
110
110
  }, ["stop"]))
111
111
  }, [
112
- e.hideHeader ? i("", !0) : (a(), w("header", {
112
+ e.hideHeader ? i("", !0) : (a(), f("header", {
113
113
  key: 0,
114
114
  "data-test": "stash-modal__header",
115
115
  class: s(["stash-modal__header tw-bg-purple tw-h-12 tw-grid tw-place-items-center", { "lg:tw-rounded-t": !n.value }])
@@ -117,16 +117,16 @@ const G = ["onKeydown"], J = ["aria-labelledby"], Q = { class: "tw-flex tw-place
117
117
  g("div", Q, [
118
118
  m(t.$slots, "headerAction", {}, void 0, !0)
119
119
  ]),
120
- e.title ? (a(), w("h3", {
120
+ e.title ? (a(), f("h3", {
121
121
  key: 0,
122
- id: f(B),
122
+ id: w(B),
123
123
  class: "tw-text-white tw-flex-1 tw-leading-6 tw-m-0"
124
124
  }, T(e.title), 9, X)) : i("", !0),
125
125
  e.hideClose ? i("", !0) : (a(), F(N, {
126
126
  key: 1,
127
127
  icon: "",
128
128
  "data-test": "ll-modal-close",
129
- title: f(M)("ll.closeModal"),
129
+ title: w(M)("ll.closeModal"),
130
130
  type: "button",
131
131
  onClick: v
132
132
  }, {
@@ -145,7 +145,7 @@ const G = ["onKeydown"], J = ["aria-labelledby"], Q = { class: "tw-flex tw-place
145
145
  icon: "",
146
146
  "data-test": "ll-modal-close",
147
147
  type: "button",
148
- title: f(M)("ll.closeModal"),
148
+ title: w(M)("ll.closeModal"),
149
149
  onClick: v
150
150
  }, {
151
151
  default: L(() => [
@@ -156,7 +156,7 @@ const G = ["onKeydown"], J = ["aria-labelledby"], Q = { class: "tw-flex tw-place
156
156
  ]),
157
157
  _: 1
158
158
  }, 8, ["title"])) : i("", !0),
159
- f(y)["featured-content"] ? (a(), w("div", {
159
+ w(y)["featured-content"] ? (a(), f("div", {
160
160
  key: 2,
161
161
  class: s(["tw-relative stash-modal__featured-content", {
162
162
  "tw-rounded-t": e.hideHeader
@@ -178,7 +178,7 @@ const G = ["onKeydown"], J = ["aria-labelledby"], Q = { class: "tw-flex tw-place
178
178
  }, [
179
179
  m(t.$slots, "default", {}, void 0, !0)
180
180
  ], 2),
181
- z.value ? (a(), w("footer", {
181
+ z.value ? (a(), f("footer", {
182
182
  key: 3,
183
183
  class: s(["stash-modal__footer tw-bg-ice-200 tw-border-ice-500 tw-p-3 lg:tw-p-6", { "lg:tw-rounded-b": !n.value }])
184
184
  }, [
@@ -192,7 +192,7 @@ const G = ["onKeydown"], J = ["aria-labelledby"], Q = { class: "tw-flex tw-place
192
192
  ], 42, G)) : i("", !0);
193
193
  }
194
194
  });
195
- const pe = /* @__PURE__ */ P(Z, [["__scopeId", "data-v-b3fbc1c9"]]);
195
+ const pe = /* @__PURE__ */ P(Z, [["__scopeId", "data-v-866f4c00"]]);
196
196
  export {
197
197
  W as ModalPosition,
198
198
  U as ModalSize,
package/dist/Modal.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.js","sources":["../src/components/Modal/Modal.types.ts","../src/components/Modal/Modal.vue"],"sourcesContent":["export enum ModalSize {\n Narrow = 'narrow',\n Medium = 'medium',\n Wide = 'wide',\n}\n\nexport type ModalSizes = `${ModalSize}`;\n\nexport enum ModalPosition {\n Center = 'center',\n Left = 'left',\n Right = 'right',\n}\n\nexport type ModalPositions = `${ModalPosition}`;\n","<script lang=\"ts\">\n import { ModalPositions, ModalSizes } from './Modal.types';\n\n export * from './Modal.types';\n\n export interface ModalProps {\n /**\n * Hides the \"close\" button\n */\n hideClose?: boolean;\n\n /**\n * Opens the modal when truthy; hides the modal when falsy.\n * @deprecated Use `isOpen` instead\n */\n open?: boolean;\n\n /**\n * Opens the modal when truthy; hides the modal when falsy.\n */\n isOpen?: boolean;\n\n /**\n * Use v-model:is-open or :is-open instead of :model-value and v-model.\n * @deprecated\n */\n modelValue?: boolean;\n\n /**\n * Sets a preset max-width on the modal.\n * Options: default (648px), narrow (360px), wide (960px)\n */\n size?: ModalSizes;\n\n /**\n * Should the modal be scrollable within the content area. This prop is treated as `true` when the `position` prop is set to \"left\" or \"right\".\n */\n scrollable?: boolean;\n\n /**\n * Gives the modal body have a light gray background\n */\n contrast?: boolean;\n\n /**\n * Text to display in the modal header\n */\n title?: string;\n\n /**\n * Disables the default padding in the modal body.\n */\n disableBodyPadding?: boolean;\n\n /**\n * The position on the screen to display the modal.\n */\n position?: ModalPositions;\n\n /**\n * Hide the header. Typically used with the featuredContent slot to display a graphic and create a \"promo\" modal.\n */\n hideHeader?: boolean;\n\n /**\n * Add classes to the close button. This can be used with the hideHeader prop and featuredContent slot to\n * accommodate images with different color backgrounds.\n */\n closeButtonColorClass?: string;\n }\n</script>\n\n<script setup lang=\"ts\">\n import uniqueId from 'lodash-es/uniqueId';\n import { computed, onBeforeUnmount, ref, useSlots, watch } from 'vue';\n\n import { FOCUS_ELEMENTS_SELECTOR } from '../../constants';\n import { t } from '../../locale';\n import Backdrop from '../Backdrop/Backdrop.vue';\n import Button from '../Button/Button.vue';\n import Icon from '../Icon/Icon.vue';\n\n defineOptions({ name: 'll-modal' });\n\n const props = withDefaults(defineProps<ModalProps>(), {\n hideClose: false,\n open: false,\n isOpen: false,\n modelValue: false,\n size: 'medium',\n scrollable: false,\n contrast: false,\n title: '',\n position: 'center',\n hideHeader: false,\n closeButtonColorClass: 'tw-text-white/50',\n });\n\n const emit =\n defineEmits<{\n /**\n * @deprecated Use the `update:is-open` event instead\n */\n (e: 'update:open', isOpen?: boolean): void;\n (e: 'update:is-open', isOpen?: boolean): void;\n (e: 'dismiss'): void;\n }>();\n\n const slots = useSlots();\n\n const rootRef = ref<HTMLElement>();\n const lastExternalFocusedElement = ref<HTMLElement>();\n const focusElements = ref<HTMLElement[]>([]);\n const firstFocusElement = ref<HTMLElement>();\n const lastFocusElement = ref<HTMLElement>();\n const initialPageScrollingElementStyle = ref({ height: '', overflow: '' });\n const headerId = uniqueId('modal-header-');\n const hasFooterContent = computed(() => !!slots.actions || !!slots.footer);\n const isModalOpen = computed(() => props.open || props.isOpen);\n const isDrawer = computed(() => props.position === 'left' || props.position === 'right');\n\n function getPageScrollingElement() {\n return (document.scrollingElement || document.body) as HTMLElement;\n }\n\n watch(\n isModalOpen,\n () => {\n if (isModalOpen.value) {\n Object.assign(initialPageScrollingElementStyle.value, {\n height: getPageScrollingElement().style.height,\n overflow: getPageScrollingElement().style.overflow,\n });\n }\n\n Object.assign(getPageScrollingElement().style, {\n overflow: isModalOpen.value ? 'hidden' : initialPageScrollingElementStyle.value.overflow, // Prevents page from scrolling when modal is open\n height: isModalOpen.value ? '100%' : initialPageScrollingElementStyle.value.height, // Ensures the backdrop covers the entire page when modal is open; see https://github.com/LeafLink/stash/pull/713#issuecomment-1184602535\n });\n },\n { immediate: true },\n );\n\n onBeforeUnmount(() => {\n // In cases where the watchEffect for isModalOpen isn't triggered while closing/nagivating away from modal, this ensures scrolling returns to normal\n Object.assign(getPageScrollingElement().style, {\n overflow: initialPageScrollingElementStyle.value.overflow,\n height: initialPageScrollingElementStyle.value.height,\n });\n\n // Clear focus trap tab listener\n document.removeEventListener('keydown', handleTab);\n lastExternalFocusedElement.value?.focus();\n });\n\n function dismiss() {\n emit('update:open', false);\n emit('update:is-open', false);\n emit('dismiss');\n }\n\n // This watcher ensures the Tab key cycles through focusable elements within the modal.\n watch(rootRef, () => {\n if (!rootRef.value) {\n return;\n }\n\n lastExternalFocusedElement.value = document.activeElement as HTMLElement;\n rootRef.value.focus();\n\n focusElements.value = Array.from(rootRef.value.querySelectorAll<HTMLElement>(FOCUS_ELEMENTS_SELECTOR));\n firstFocusElement.value = focusElements.value[0];\n lastFocusElement.value = focusElements.value[focusElements.value.length - 1];\n document.addEventListener('keydown', handleTab);\n });\n\n function handleTab(e) {\n if (e.key === 'Tab') {\n if (e.shiftKey && document.activeElement === firstFocusElement.value) {\n lastFocusElement.value?.focus();\n e.preventDefault();\n } else if (document.activeElement === lastFocusElement.value) {\n firstFocusElement.value?.focus();\n e.preventDefault();\n }\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"isModalOpen\"\n ref=\"rootRef\"\n class=\"stash-modal tw-fixed tw-inset-0 tw-overflow-y-auto\"\n :class=\"{\n 'tw-invisible tw-z-behind': !isModalOpen,\n 'tw-visible tw-z-modal': isModalOpen,\n 'lg:tw-flex lg:tw-flex-col lg:tw-justify-center lg:tw-items-center': props.position === 'center',\n }\"\n data-test=\"ll-modal\"\n tabindex=\"0\"\n @keydown.esc=\"dismiss\"\n >\n <Backdrop class=\"stash-modal__backdrop\" @click.stop=\"dismiss\" />\n <div\n aria-modal=\"true\"\n role=\"dialog\"\n :aria-labelledby=\"headerId\"\n class=\"stash-modal__dialog tw-flex tw-flex-col tw-h-screen tw-w-full lg:tw-shadow-low tw-relative\"\n :class=\"[\n `stash-modal__dialog--size-${props.size}`,\n `stash-modal__dialog--position-${props.position}`,\n {\n 'stash-modal__dialog--is-open': isModalOpen,\n 'stash-modal__dialog--is-drawer': isDrawer,\n 'stash-modal__dialog--is-contrast': props.contrast,\n 'stash-modal__dialog--is-scrollable': props.scrollable,\n 'lg:tw-w-[360px]': props.size === 'narrow',\n 'lg:tw-w-[648px]': props.size === 'medium',\n 'lg:tw-w-[960px]': props.size === 'wide',\n 'lg:tw-h-auto lg:tw-my-0 lg:tw-max-h-[90vh]': props.position === 'center',\n 'lg:tw-h-screen lg:tw-absolute': isDrawer,\n 'lg:tw-left-0': props.position === 'left',\n 'lg:tw-right-0': props.position === 'right',\n },\n ]\"\n @click.stop\n >\n <header\n v-if=\"!props.hideHeader\"\n data-test=\"stash-modal__header\"\n class=\"stash-modal__header tw-bg-purple tw-h-12 tw-grid tw-place-items-center\"\n :class=\"{ 'lg:tw-rounded-t': !isDrawer }\"\n >\n <div class=\"tw-flex tw-place-items-center\">\n <!-- @slot Adds an action to the left side of the header bar. An example usage is a modal with multiple pages and a back button can be inserted here -->\n <slot name=\"headerAction\"></slot>\n </div>\n\n <h3 v-if=\"props.title\" :id=\"headerId\" class=\"tw-text-white tw-flex-1 tw-leading-6 tw-m-0\">\n {{ props.title }}\n </h3>\n\n <Button\n v-if=\"!props.hideClose\"\n icon\n data-test=\"ll-modal-close\"\n :title=\"t('ll.closeModal')\"\n type=\"button\"\n @click=\"dismiss\"\n >\n <Icon class=\"tw-text-white\" name=\"close\" />\n </Button>\n </header>\n\n <Button\n v-if=\"!props.hideClose && props.hideHeader\"\n class=\"tw-absolute tw-right-0 tw-top-0 tw-z-10\"\n icon\n data-test=\"ll-modal-close\"\n type=\"button\"\n :title=\"t('ll.closeModal')\"\n @click=\"dismiss\"\n >\n <Icon class=\"tw-drop-shadow-md\" name=\"close\" :class=\"[props.closeButtonColorClass]\" />\n </Button>\n\n <div\n v-if=\"!!slots['featured-content']\"\n class=\"tw-relative stash-modal__featured-content\"\n :class=\"{\n 'tw-rounded-t': props.hideHeader,\n }\"\n >\n <slot name=\"featured-content\"></slot>\n </div>\n\n <div\n class=\"stash-modal__body tw-flex-1 tw-overflow-y-auto\"\n :class=\"[\n {\n 'tw-p-3 lg:tw-p-6': !props.disableBodyPadding,\n 'lg:tw-overflow-y-visible': !props.scrollable && !isDrawer,\n 'lg:tw-rounded-b': !hasFooterContent && !isDrawer,\n 'tw-bg-white': !props.contrast,\n 'tw-bg-ice-200': props.contrast,\n },\n ]\"\n data-test=\"stash-modal__body\"\n >\n <slot></slot>\n </div>\n\n <footer\n v-if=\"hasFooterContent\"\n class=\"stash-modal__footer tw-bg-ice-200 tw-border-ice-500 tw-p-3 lg:tw-p-6\"\n :class=\"{ 'lg:tw-rounded-b': !isDrawer }\"\n >\n <!-- @slot Overrides the whole footer section. Used for rendering custom footers with more than 2 actions. If defined, \"actions\" slot will get ignored. -->\n <slot name=\"footer\">\n <div class=\"stash-modal__footer__actions tw-flex tw-flex-col tw-justify-end lg:tw-flex-row\">\n <!-- @slot Modal footer actions, supports rendering up to 2 `<Button>` children -->\n <slot name=\"actions\"></slot>\n </div>\n </slot>\n </footer>\n </div>\n </div>\n</template>\n\n<style scoped>\n .stash-modal__header {\n grid-template-columns: 48px 1fr 48px;\n }\n\n .stash-modal__footer__actions > :deep(.stash-button):nth-of-type(1) {\n order: 2;\n }\n\n .stash-modal__footer__actions > :deep(.stash-button):nth-of-type(2) {\n margin-bottom: var(--ll-space-2);\n order: 1;\n }\n\n @media screen and (width >= 961px) {\n .stash-modal__footer__actions > :deep(.stash-button):nth-of-type(1) {\n order: 1;\n }\n\n .stash-modal__footer__actions > :deep(.stash-button):nth-of-type(2) {\n margin-bottom: 0;\n order: 2;\n }\n\n .stash-modal__footer__actions > :deep(.stash-button + .stash-button) {\n margin-left: var(--grid-gutter);\n }\n }\n\n .stash-modal__featured-content > :deep(*) {\n border-radius: inherit;\n }\n</style>\n"],"names":["ModalSize","ModalPosition","slots","useSlots","rootRef","ref","lastExternalFocusedElement","focusElements","firstFocusElement","lastFocusElement","initialPageScrollingElementStyle","headerId","uniqueId","hasFooterContent","computed","isModalOpen","props","isDrawer","getPageScrollingElement","watch","onBeforeUnmount","handleTab","_a","dismiss","emit","FOCUS_ELEMENTS_SELECTOR","e","_b"],"mappings":";;;;;;;;;;;;;;;AAAY,IAAAA,sBAAAA,OACVA,EAAA,SAAS,UACTA,EAAA,SAAS,UACTA,EAAA,OAAO,QAHGA,IAAAA,KAAA,CAAA,CAAA,GAQAC,sBAAAA,OACVA,EAAA,SAAS,UACTA,EAAA,OAAO,QACPA,EAAA,QAAQ,SAHEA,IAAAA,KAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;iBCoGJC,IAAQC,KAERC,IAAUC,KACVC,IAA6BD,KAC7BE,IAAgBF,EAAmB,CAAA,CAAE,GACrCG,IAAoBH,KACpBI,IAAmBJ,KACnBK,IAAmCL,EAAI,EAAE,QAAQ,IAAI,UAAU,IAAI,GACnEM,IAAWC,EAAS,eAAe,GACnCC,IAAmBC,EAAS,MAAM,CAAC,CAACZ,EAAM,WAAW,CAAC,CAACA,EAAM,MAAM,GACnEa,IAAcD,EAAS,MAAME,EAAM,QAAQA,EAAM,MAAM,GACvDC,IAAWH,EAAS,MAAME,EAAM,aAAa,UAAUA,EAAM,aAAa,OAAO;AAEvF,aAASE,IAA0B;AACzB,aAAA,SAAS,oBAAoB,SAAS;AAAA,IAChD;AAEA,IAAAC;AAAA,MACEJ;AAAA,MACA,MAAM;AACJ,QAAIA,EAAY,SACP,OAAA,OAAOL,EAAiC,OAAO;AAAA,UACpD,QAAQQ,IAA0B,MAAM;AAAA,UACxC,UAAUA,IAA0B,MAAM;AAAA,QAAA,CAC3C,GAGI,OAAA,OAAOA,EAAwB,EAAE,OAAO;AAAA,UAC7C,UAAUH,EAAY,QAAQ,WAAWL,EAAiC,MAAM;AAAA;AAAA,UAChF,QAAQK,EAAY,QAAQ,SAASL,EAAiC,MAAM;AAAA;AAAA,QAAA,CAC7E;AAAA,MACH;AAAA,MACA,EAAE,WAAW,GAAK;AAAA,IAAA,GAGpBU,EAAgB,MAAM;;AAEb,aAAA,OAAOF,EAAwB,EAAE,OAAO;AAAA,QAC7C,UAAUR,EAAiC,MAAM;AAAA,QACjD,QAAQA,EAAiC,MAAM;AAAA,MAAA,CAChD,GAGQ,SAAA,oBAAoB,WAAWW,CAAS,IACjDC,IAAAhB,EAA2B,UAA3B,QAAAgB,EAAkC;AAAA,IAAM,CACzC;AAED,aAASC,IAAU;AACjB,MAAAC,EAAK,eAAe,EAAK,GACzBA,EAAK,kBAAkB,EAAK,GAC5BA,EAAK,SAAS;AAAA,IAChB;AAGA,IAAAL,EAAMf,GAAS,MAAM;AACf,MAACA,EAAQ,UAIbE,EAA2B,QAAQ,SAAS,eAC5CF,EAAQ,MAAM,SAEdG,EAAc,QAAQ,MAAM,KAAKH,EAAQ,MAAM,iBAA8BqB,CAAuB,CAAC,GACnFjB,EAAA,QAAQD,EAAc,MAAM,CAAC,GAC/CE,EAAiB,QAAQF,EAAc,MAAMA,EAAc,MAAM,SAAS,CAAC,GAClE,SAAA,iBAAiB,WAAWc,CAAS;AAAA,IAAA,CAC/C;AAED,aAASA,EAAUK,GAAG;;AAChB,MAAAA,EAAE,QAAQ,UACRA,EAAE,YAAY,SAAS,kBAAkBlB,EAAkB,UAC7Dc,IAAAb,EAAiB,UAAjB,QAAAa,EAAwB,SACxBI,EAAE,eAAe,KACR,SAAS,kBAAkBjB,EAAiB,WACrDkB,IAAAnB,EAAkB,UAAlB,QAAAmB,EAAyB,SACzBD,EAAE,eAAe;AAAA,IAGvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"Modal.js","sources":["../src/components/Modal/Modal.types.ts","../src/components/Modal/Modal.vue"],"sourcesContent":["export enum ModalSize {\n Narrow = 'narrow',\n Medium = 'medium',\n Wide = 'wide',\n}\n\nexport type ModalSizes = `${ModalSize}`;\n\nexport enum ModalPosition {\n Center = 'center',\n Left = 'left',\n Right = 'right',\n}\n\nexport type ModalPositions = `${ModalPosition}`;\n","<script lang=\"ts\">\n import { ModalPositions, ModalSizes } from './Modal.types';\n\n export * from './Modal.types';\n\n export interface ModalProps {\n /**\n * Hides the \"close\" button\n */\n hideClose?: boolean;\n\n /**\n * Opens the modal when truthy; hides the modal when falsy.\n * @deprecated Use `isOpen` instead\n */\n open?: boolean;\n\n /**\n * Opens the modal when truthy; hides the modal when falsy.\n */\n isOpen?: boolean;\n\n /**\n * Use v-model:is-open or :is-open instead of :model-value and v-model.\n * @deprecated\n */\n modelValue?: boolean;\n\n /**\n * Sets a preset max-width on the modal.\n * Options: default (648px), narrow (360px), wide (960px)\n */\n size?: ModalSizes;\n\n /**\n * Should the modal be scrollable within the content area. This prop is treated as `true` when the `position` prop is set to \"left\" or \"right\".\n */\n scrollable?: boolean;\n\n /**\n * Gives the modal body have a light gray background\n */\n contrast?: boolean;\n\n /**\n * Text to display in the modal header\n */\n title?: string;\n\n /**\n * Disables the default padding in the modal body.\n */\n disableBodyPadding?: boolean;\n\n /**\n * The position on the screen to display the modal.\n */\n position?: ModalPositions;\n\n /**\n * Hide the header. Typically used with the featuredContent slot to display a graphic and create a \"promo\" modal.\n */\n hideHeader?: boolean;\n\n /**\n * Add classes to the close button. This can be used with the hideHeader prop and featuredContent slot to\n * accommodate images with different color backgrounds.\n */\n closeButtonColorClass?: string;\n }\n</script>\n\n<script setup lang=\"ts\">\n import uniqueId from 'lodash-es/uniqueId';\n import { computed, onBeforeUnmount, ref, useSlots, watch } from 'vue';\n\n import { FOCUS_ELEMENTS_SELECTOR } from '../../constants';\n import { t } from '../../locale';\n import Backdrop from '../Backdrop/Backdrop.vue';\n import Button from '../Button/Button.vue';\n import Icon from '../Icon/Icon.vue';\n\n defineOptions({ name: 'll-modal' });\n\n const props = withDefaults(defineProps<ModalProps>(), {\n hideClose: false,\n open: false,\n isOpen: false,\n modelValue: false,\n size: 'medium',\n scrollable: false,\n contrast: false,\n title: '',\n position: 'center',\n hideHeader: false,\n closeButtonColorClass: 'tw-text-white/50',\n });\n\n const emit =\n defineEmits<{\n /**\n * @deprecated Use the `update:is-open` event instead\n */\n (e: 'update:open', isOpen?: boolean): void;\n (e: 'update:is-open', isOpen?: boolean): void;\n (e: 'dismiss'): void;\n }>();\n\n const slots = useSlots();\n\n const rootRef = ref<HTMLElement>();\n const lastExternalFocusedElement = ref<HTMLElement>();\n const focusElements = ref<HTMLElement[]>([]);\n const firstFocusElement = ref<HTMLElement>();\n const lastFocusElement = ref<HTMLElement>();\n const initialPageScrollingElementStyle = ref({ height: '', overflow: '' });\n const headerId = uniqueId('modal-header-');\n const hasFooterContent = computed(() => !!slots.actions || !!slots.footer);\n const isModalOpen = computed(() => props.open || props.isOpen);\n const isDrawer = computed(() => props.position === 'left' || props.position === 'right');\n\n function getPageScrollingElement() {\n return (document.scrollingElement || document.body) as HTMLElement;\n }\n\n watch(\n isModalOpen,\n () => {\n if (isModalOpen.value) {\n Object.assign(initialPageScrollingElementStyle.value, {\n height: getPageScrollingElement().style.height,\n overflow: getPageScrollingElement().style.overflow,\n });\n }\n\n Object.assign(getPageScrollingElement().style, {\n overflow: isModalOpen.value ? 'hidden' : initialPageScrollingElementStyle.value.overflow, // Prevents page from scrolling when modal is open\n height: isModalOpen.value ? '100%' : initialPageScrollingElementStyle.value.height, // Ensures the backdrop covers the entire page when modal is open; see https://github.com/LeafLink/stash/pull/713#issuecomment-1184602535\n });\n },\n { immediate: true },\n );\n\n onBeforeUnmount(() => {\n // In cases where the watchEffect for isModalOpen isn't triggered while closing/nagivating away from modal, this ensures scrolling returns to normal\n Object.assign(getPageScrollingElement().style, {\n overflow: initialPageScrollingElementStyle.value.overflow,\n height: initialPageScrollingElementStyle.value.height,\n });\n\n // Clear focus trap tab listener\n document.removeEventListener('keydown', handleTab);\n lastExternalFocusedElement.value?.focus();\n });\n\n function dismiss() {\n emit('update:open', false);\n emit('update:is-open', false);\n emit('dismiss');\n }\n\n // This watcher ensures the Tab key cycles through focusable elements within the modal.\n watch(rootRef, () => {\n if (!rootRef.value) {\n return;\n }\n\n lastExternalFocusedElement.value = document.activeElement as HTMLElement;\n rootRef.value.focus();\n\n focusElements.value = Array.from(rootRef.value.querySelectorAll<HTMLElement>(FOCUS_ELEMENTS_SELECTOR));\n firstFocusElement.value = focusElements.value[0];\n lastFocusElement.value = focusElements.value[focusElements.value.length - 1];\n document.addEventListener('keydown', handleTab);\n });\n\n function handleTab(e) {\n if (e.key === 'Tab') {\n if (e.shiftKey && document.activeElement === firstFocusElement.value) {\n lastFocusElement.value?.focus();\n e.preventDefault();\n } else if (document.activeElement === lastFocusElement.value) {\n firstFocusElement.value?.focus();\n e.preventDefault();\n }\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"isModalOpen\"\n ref=\"rootRef\"\n class=\"stash-modal tw-fixed tw-inset-0 tw-overflow-y-auto\"\n :class=\"{\n 'tw-invisible tw-z-behind': !isModalOpen,\n 'tw-visible tw-z-modal': isModalOpen,\n 'lg:tw-flex lg:tw-flex-col lg:tw-justify-center lg:tw-items-center': props.position === 'center',\n }\"\n data-test=\"ll-modal\"\n tabindex=\"0\"\n @keydown.esc=\"dismiss\"\n >\n <Backdrop class=\"stash-modal__backdrop\" @click.stop=\"dismiss\" />\n <div\n aria-modal=\"true\"\n role=\"dialog\"\n :aria-labelledby=\"headerId\"\n class=\"stash-modal__dialog tw-flex tw-flex-col tw-h-screen tw-w-full lg:tw-shadow tw-relative\"\n :class=\"[\n `stash-modal__dialog--size-${props.size}`,\n `stash-modal__dialog--position-${props.position}`,\n {\n 'stash-modal__dialog--is-open': isModalOpen,\n 'stash-modal__dialog--is-drawer': isDrawer,\n 'stash-modal__dialog--is-contrast': props.contrast,\n 'stash-modal__dialog--is-scrollable': props.scrollable,\n 'lg:tw-w-[360px]': props.size === 'narrow',\n 'lg:tw-w-[648px]': props.size === 'medium',\n 'lg:tw-w-[960px]': props.size === 'wide',\n 'lg:tw-h-auto lg:tw-my-0 lg:tw-max-h-[90vh]': props.position === 'center',\n 'lg:tw-h-screen lg:tw-absolute': isDrawer,\n 'lg:tw-left-0': props.position === 'left',\n 'lg:tw-right-0': props.position === 'right',\n },\n ]\"\n @click.stop\n >\n <header\n v-if=\"!props.hideHeader\"\n data-test=\"stash-modal__header\"\n class=\"stash-modal__header tw-bg-purple tw-h-12 tw-grid tw-place-items-center\"\n :class=\"{ 'lg:tw-rounded-t': !isDrawer }\"\n >\n <div class=\"tw-flex tw-place-items-center\">\n <!-- @slot Adds an action to the left side of the header bar. An example usage is a modal with multiple pages and a back button can be inserted here -->\n <slot name=\"headerAction\"></slot>\n </div>\n\n <h3 v-if=\"props.title\" :id=\"headerId\" class=\"tw-text-white tw-flex-1 tw-leading-6 tw-m-0\">\n {{ props.title }}\n </h3>\n\n <Button\n v-if=\"!props.hideClose\"\n icon\n data-test=\"ll-modal-close\"\n :title=\"t('ll.closeModal')\"\n type=\"button\"\n @click=\"dismiss\"\n >\n <Icon class=\"tw-text-white\" name=\"close\" />\n </Button>\n </header>\n\n <Button\n v-if=\"!props.hideClose && props.hideHeader\"\n class=\"tw-absolute tw-right-0 tw-top-0 tw-z-10\"\n icon\n data-test=\"ll-modal-close\"\n type=\"button\"\n :title=\"t('ll.closeModal')\"\n @click=\"dismiss\"\n >\n <Icon class=\"tw-drop-shadow-md\" name=\"close\" :class=\"[props.closeButtonColorClass]\" />\n </Button>\n\n <div\n v-if=\"!!slots['featured-content']\"\n class=\"tw-relative stash-modal__featured-content\"\n :class=\"{\n 'tw-rounded-t': props.hideHeader,\n }\"\n >\n <slot name=\"featured-content\"></slot>\n </div>\n\n <div\n class=\"stash-modal__body tw-flex-1 tw-overflow-y-auto\"\n :class=\"[\n {\n 'tw-p-3 lg:tw-p-6': !props.disableBodyPadding,\n 'lg:tw-overflow-y-visible': !props.scrollable && !isDrawer,\n 'lg:tw-rounded-b': !hasFooterContent && !isDrawer,\n 'tw-bg-white': !props.contrast,\n 'tw-bg-ice-200': props.contrast,\n },\n ]\"\n data-test=\"stash-modal__body\"\n >\n <slot></slot>\n </div>\n\n <footer\n v-if=\"hasFooterContent\"\n class=\"stash-modal__footer tw-bg-ice-200 tw-border-ice-500 tw-p-3 lg:tw-p-6\"\n :class=\"{ 'lg:tw-rounded-b': !isDrawer }\"\n >\n <!-- @slot Overrides the whole footer section. Used for rendering custom footers with more than 2 actions. If defined, \"actions\" slot will get ignored. -->\n <slot name=\"footer\">\n <div class=\"stash-modal__footer__actions tw-flex tw-flex-col tw-justify-end lg:tw-flex-row\">\n <!-- @slot Modal footer actions, supports rendering up to 2 `<Button>` children -->\n <slot name=\"actions\"></slot>\n </div>\n </slot>\n </footer>\n </div>\n </div>\n</template>\n\n<style scoped>\n .stash-modal__header {\n grid-template-columns: 48px 1fr 48px;\n }\n\n .stash-modal__footer__actions > :deep(.stash-button):nth-of-type(1) {\n order: 2;\n }\n\n .stash-modal__footer__actions > :deep(.stash-button):nth-of-type(2) {\n margin-bottom: var(--ll-space-2);\n order: 1;\n }\n\n @media screen and (width >= 961px) {\n .stash-modal__footer__actions > :deep(.stash-button):nth-of-type(1) {\n order: 1;\n }\n\n .stash-modal__footer__actions > :deep(.stash-button):nth-of-type(2) {\n margin-bottom: 0;\n order: 2;\n }\n\n .stash-modal__footer__actions > :deep(.stash-button + .stash-button) {\n margin-left: var(--grid-gutter);\n }\n }\n\n .stash-modal__featured-content > :deep(*) {\n border-radius: inherit;\n }\n</style>\n"],"names":["ModalSize","ModalPosition","slots","useSlots","rootRef","ref","lastExternalFocusedElement","focusElements","firstFocusElement","lastFocusElement","initialPageScrollingElementStyle","headerId","uniqueId","hasFooterContent","computed","isModalOpen","props","isDrawer","getPageScrollingElement","watch","onBeforeUnmount","handleTab","_a","dismiss","emit","FOCUS_ELEMENTS_SELECTOR","e","_b"],"mappings":";;;;;;;;;;;;;;;AAAY,IAAAA,sBAAAA,OACVA,EAAA,SAAS,UACTA,EAAA,SAAS,UACTA,EAAA,OAAO,QAHGA,IAAAA,KAAA,CAAA,CAAA,GAQAC,sBAAAA,OACVA,EAAA,SAAS,UACTA,EAAA,OAAO,QACPA,EAAA,QAAQ,SAHEA,IAAAA,KAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;iBCoGJC,IAAQC,KAERC,IAAUC,KACVC,IAA6BD,KAC7BE,IAAgBF,EAAmB,CAAA,CAAE,GACrCG,IAAoBH,KACpBI,IAAmBJ,KACnBK,IAAmCL,EAAI,EAAE,QAAQ,IAAI,UAAU,IAAI,GACnEM,IAAWC,EAAS,eAAe,GACnCC,IAAmBC,EAAS,MAAM,CAAC,CAACZ,EAAM,WAAW,CAAC,CAACA,EAAM,MAAM,GACnEa,IAAcD,EAAS,MAAME,EAAM,QAAQA,EAAM,MAAM,GACvDC,IAAWH,EAAS,MAAME,EAAM,aAAa,UAAUA,EAAM,aAAa,OAAO;AAEvF,aAASE,IAA0B;AACzB,aAAA,SAAS,oBAAoB,SAAS;AAAA,IAChD;AAEA,IAAAC;AAAA,MACEJ;AAAA,MACA,MAAM;AACJ,QAAIA,EAAY,SACP,OAAA,OAAOL,EAAiC,OAAO;AAAA,UACpD,QAAQQ,IAA0B,MAAM;AAAA,UACxC,UAAUA,IAA0B,MAAM;AAAA,QAAA,CAC3C,GAGI,OAAA,OAAOA,EAAwB,EAAE,OAAO;AAAA,UAC7C,UAAUH,EAAY,QAAQ,WAAWL,EAAiC,MAAM;AAAA;AAAA,UAChF,QAAQK,EAAY,QAAQ,SAASL,EAAiC,MAAM;AAAA;AAAA,QAAA,CAC7E;AAAA,MACH;AAAA,MACA,EAAE,WAAW,GAAK;AAAA,IAAA,GAGpBU,EAAgB,MAAM;;AAEb,aAAA,OAAOF,EAAwB,EAAE,OAAO;AAAA,QAC7C,UAAUR,EAAiC,MAAM;AAAA,QACjD,QAAQA,EAAiC,MAAM;AAAA,MAAA,CAChD,GAGQ,SAAA,oBAAoB,WAAWW,CAAS,IACjDC,IAAAhB,EAA2B,UAA3B,QAAAgB,EAAkC;AAAA,IAAM,CACzC;AAED,aAASC,IAAU;AACjB,MAAAC,EAAK,eAAe,EAAK,GACzBA,EAAK,kBAAkB,EAAK,GAC5BA,EAAK,SAAS;AAAA,IAChB;AAGA,IAAAL,EAAMf,GAAS,MAAM;AACf,MAACA,EAAQ,UAIbE,EAA2B,QAAQ,SAAS,eAC5CF,EAAQ,MAAM,SAEdG,EAAc,QAAQ,MAAM,KAAKH,EAAQ,MAAM,iBAA8BqB,CAAuB,CAAC,GACnFjB,EAAA,QAAQD,EAAc,MAAM,CAAC,GAC/CE,EAAiB,QAAQF,EAAc,MAAMA,EAAc,MAAM,SAAS,CAAC,GAClE,SAAA,iBAAiB,WAAWc,CAAS;AAAA,IAAA,CAC/C;AAED,aAASA,EAAUK,GAAG;;AAChB,MAAAA,EAAE,QAAQ,UACRA,EAAE,YAAY,SAAS,kBAAkBlB,EAAkB,UAC7Dc,IAAAb,EAAiB,UAAjB,QAAAa,EAAwB,SACxBI,EAAE,eAAe,KACR,SAAS,kBAAkBjB,EAAiB,WACrDkB,IAAAnB,EAAkB,UAAlB,QAAAmB,EAAyB,SACzBD,EAAE,eAAe;AAAA,IAGvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}