@leaflink/stash 47.2.1 → 47.3.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/README.md CHANGED
@@ -178,7 +178,6 @@ interface StashPluginOptions {
178
178
 
179
179
  interface StashOptionImages {
180
180
  provider: StashImageProviders; // 'cloudinary' | 'static'
181
- staticDomains: string[];
182
181
  }
183
182
 
184
183
  interface ModalsPluginOptions {
package/dist/Image.js CHANGED
@@ -1,38 +1,33 @@
1
- import { defineComponent as M, inject as B, computed as o, useAttrs as D, openBlock as L, createElementBlock as k, mergeProps as C, unref as N } from "vue";
2
- import V from "@leaflink/snitch";
3
- import { IMAGE_PROVIDER_URLS as q, SCREEN_SIZES as y } from "./constants.js";
4
- import G from "lodash-es/merge";
5
- const w = {
1
+ import { defineComponent as W, inject as A, computed as c, useAttrs as M, openBlock as B, createElementBlock as k, mergeProps as C, unref as L } from "vue";
2
+ import { IMAGE_PROVIDER_URLS as N, SCREEN_SIZES as y } from "./constants.js";
3
+ import q from "lodash-es/merge";
4
+ const $ = {
6
5
  xs: 160,
7
6
  sm: 338,
8
7
  md: 676,
9
8
  lg: 1352,
10
9
  xl: 2704
11
10
  };
12
- var P = /* @__PURE__ */ ((e) => (e.None = "none", e.Rounded = "rounded", e))(P || {}), z = /* @__PURE__ */ ((e) => (e.Cloudinary = "cloudinary", e.Static = "static", e))(z || {});
11
+ var w = /* @__PURE__ */ ((e) => (e.None = "none", e.Rounded = "rounded", e))(w || {}), z = /* @__PURE__ */ ((e) => (e.Cloudinary = "cloudinary", e.Static = "static", e))(z || {});
13
12
  function j(e) {
14
13
  return (t) => e[t] || t;
15
14
  }
16
- function Q({
17
- formatter: e = (u, c) => `${u}=${c}`,
15
+ function G({
16
+ formatter: e = (m, i) => `${m}=${i}`,
18
17
  keyMap: t,
19
- joinWith: d = "/",
20
- valueMap: r = {}
18
+ joinWith: f = "/",
19
+ valueMap: s = {}
21
20
  } = {}) {
22
- const u = typeof t == "function" ? t : j(t || {});
23
- return Object.keys(r).forEach((c) => {
24
- typeof r[c] != "function" && (r[c] = j(r[c]));
25
- }), (c = {}) => Object.entries(c).map(([f, g]) => {
26
- const p = r[f], l = u(f);
27
- let v = g;
28
- return typeof p == "function" && (v = p(c[f])), e(l, v);
29
- }).join(d);
21
+ const m = typeof t == "function" ? t : j(t || {});
22
+ return Object.keys(s).forEach((i) => {
23
+ typeof s[i] != "function" && (s[i] = j(s[i]));
24
+ }), (i = {}) => Object.entries(i).map(([u, d]) => {
25
+ const p = s[u], g = m(u);
26
+ let v = d;
27
+ return typeof p == "function" && (v = p(i[u])), e(g, v);
28
+ }).join(f);
30
29
  }
31
- function T(e = "", t = []) {
32
- const r = new URL(e).host;
33
- return t.some((u) => u === r ? !0 : u.endsWith(`.${r}`));
34
- }
35
- const F = q.CLOUDINARY, H = (e) => e.startsWith("#") ? e.replace("#", "rgb_") : e, I = Q({
30
+ const Q = N.CLOUDINARY, T = (e) => e.startsWith("#") ? e.replace("#", "rgb_") : e, P = G({
36
31
  keyMap: {
37
32
  fit: "c",
38
33
  width: "w",
@@ -54,34 +49,34 @@ const F = q.CLOUDINARY, H = (e) => e.startsWith("#") ? e.replace("#", "rgb_") :
54
49
  jpeg: "jpg"
55
50
  },
56
51
  background(e) {
57
- return H(e);
52
+ return T(e);
58
53
  }
59
54
  },
60
55
  joinWith: ",",
61
56
  formatter: (e, t) => `${e}_${t}`
62
- }), Y = {
57
+ }), D = {
63
58
  format: "auto",
64
59
  quality: "auto:best"
65
60
  };
66
- function Z(e, t = {}) {
67
- const d = G(Y, t), r = I(d);
68
- return `${F}/${r}/${e}`;
61
+ function F(e, t = {}) {
62
+ const f = q(D, t), s = P(f);
63
+ return `${Q}/${s}/${e}`;
69
64
  }
70
- const J = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
65
+ const V = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
71
66
  __proto__: null,
72
- getImageUrl: Z,
73
- operationsGenerator: I
67
+ getImageUrl: F,
68
+ operationsGenerator: P
74
69
  }, Symbol.toStringTag, { value: "Module" }));
75
- function K(e = "") {
70
+ function H(e = "") {
76
71
  return e;
77
72
  }
78
- const X = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
73
+ const Y = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
79
74
  __proto__: null,
80
- getImageUrl: K
81
- }, Symbol.toStringTag, { value: "Module" })), tt = {
82
- cloudinary: J,
83
- static: X
84
- }, et = ["src"], it = /* @__PURE__ */ M({
75
+ getImageUrl: H
76
+ }, Symbol.toStringTag, { value: "Module" })), Z = {
77
+ cloudinary: V,
78
+ static: Y
79
+ }, J = ["src"], et = /* @__PURE__ */ W({
85
80
  __name: "Image",
86
81
  props: {
87
82
  src: { default: "" },
@@ -92,86 +87,81 @@ const X = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
92
87
  staticPath: { default: void 0 }
93
88
  },
94
89
  setup(e) {
95
- const t = e, d = {
90
+ const t = e, f = {
96
91
  md: y.md,
97
92
  lg: y.lg
98
- }, r = B("stashOptions"), u = o(() => {
99
- const { src: n, ...s } = D();
100
- return s.sizes = U.value, s.srcset = E.value, s;
101
- }), c = o(() => {
102
- var n;
103
- return ((n = r == null ? void 0 : r.images) == null ? void 0 : n.staticDomains) || [];
104
- }), S = o(() => {
93
+ }, s = A("stashOptions"), m = c(() => {
94
+ const { src: r, ...n } = M();
95
+ return n.sizes = v.value, n.srcset = E.value, n;
96
+ }), i = c(() => {
105
97
  try {
106
98
  return new URL(t.src), !0;
107
99
  } catch {
108
100
  return !1;
109
101
  }
110
- }), f = o(() => S.value && T(t.src, c.value)), g = o(() => {
111
- var n;
112
- return t.provider || ((n = r == null ? void 0 : r.images) == null ? void 0 : n.provider) || z.Static;
113
- }), p = o(() => t.staticPath || (r == null ? void 0 : r.staticPath)), l = o(() => g.value === z.Static), v = o(() => tt[g.value]), $ = o(() => l.value ? _() : _({ width: w.md })), U = o(() => t.sizes ? x() : t.sizes), E = o(() => t.sizes && !t.srcset && !l.value ? W() : t.srcset), R = o(() => t.sizes ? A(t.sizes) : []);
114
- function _(n = {}) {
115
- if (l.value && S.value && !f.value)
116
- return V.error(`Image: ${t.src} is not from a whitelisted domain. See \`stashOptions.image.domains\`.`), "";
117
- if (l.value && f.value)
102
+ }), S = c(() => {
103
+ var r;
104
+ return t.provider || ((r = s == null ? void 0 : s.images) == null ? void 0 : r.provider) || z.Static;
105
+ }), u = c(() => t.staticPath ?? (s == null ? void 0 : s.staticPath)), d = c(() => S.value === z.Static), p = c(() => Z[S.value]), g = c(() => d.value ? _() : _({ width: $.md })), v = c(() => t.sizes ? U() : t.sizes), E = c(() => t.sizes && !t.srcset && !d.value ? R() : t.srcset), I = c(() => t.sizes ? O(t.sizes) : []);
106
+ function _(r = {}) {
107
+ if (d.value && i.value)
118
108
  return t.src;
119
- const s = l.value && p.value ? `${p.value}/${t.src}` : t.src;
120
- return v.value.getImageUrl(s, n);
109
+ const n = d.value && u.value ? `${u.value}/${t.src}` : t.src;
110
+ return p.value.getImageUrl(n, r);
121
111
  }
122
- function W() {
123
- return Object.values(w).map((n) => `${_({ width: n })} ${n}w`).join(", ");
112
+ function R() {
113
+ return Object.values($).map((r) => `${_({ width: r })} ${r}w`).join(", ");
124
114
  }
125
- function x() {
126
- var n;
127
- return (n = t.sizes) != null && n.includes("(") ? t.sizes : R.value.map((s) => `${s.mediaQuery ? s.mediaQuery + " " : ""}${s.size}`).join(", ");
115
+ function U() {
116
+ var r;
117
+ return (r = t.sizes) != null && r.includes("(") ? t.sizes : I.value.map((n) => `${n.mediaQuery ? n.mediaQuery + " " : ""}${n.size}`).join(", ");
128
118
  }
129
- function A(n = "") {
130
- const s = [], h = {
119
+ function O(r = "") {
120
+ const n = [], h = {
131
121
  default: "100vw"
132
122
  };
133
- if (typeof n == "string") {
134
- const m = n.split(/[\s]+/).filter((a) => a);
135
- for (const a of m) {
136
- const i = a.split(":");
137
- if (i.length !== 2) {
138
- h.default = i[0].trim();
123
+ if (typeof r == "string") {
124
+ const l = r.split(/[\s]+/).filter((a) => a);
125
+ for (const a of l) {
126
+ const o = a.split(":");
127
+ if (o.length !== 2) {
128
+ h.default = o[0].trim();
139
129
  continue;
140
130
  }
141
- h[i[0].trim()] = i[1].trim();
131
+ h[o[0].trim()] = o[1].trim();
142
132
  }
143
133
  } else
144
134
  throw new Error("`sizes` needs to be a string");
145
- for (const m in h) {
146
- const a = parseInt(d[m] || 0);
147
- let i = String(h[m]);
148
- const b = i.endsWith("vw");
149
- if (!b && /^\d+$/.test(i) && (i = `${i}px`), !b && i.endsWith("%"))
135
+ for (const l in h) {
136
+ const a = parseInt(f[l] || 0);
137
+ let o = String(h[l]);
138
+ const b = o.endsWith("vw");
139
+ if (!b && /^\d+$/.test(o) && (o = `${o}px`), !b && o.endsWith("%"))
150
140
  throw new Error("Image: `sizes` does not support percentage values");
151
- const O = {
141
+ const x = {
152
142
  mediaQuery: a ? `(min-width: ${a}px)` : "",
153
143
  screenMinWidth: a,
154
- size: i
144
+ size: o
155
145
  };
156
- s.push(O);
146
+ n.push(x);
157
147
  }
158
- return s.sort((m, a) => m.screenMinWidth > a.screenMinWidth ? -1 : 1), s;
148
+ return n.sort((l, a) => l.screenMinWidth > a.screenMinWidth ? -1 : 1), n;
159
149
  }
160
- return (n, s) => (L(), k("img", C({
150
+ return (r, n) => (B(), k("img", C({
161
151
  ref: "img",
162
- key: $.value,
152
+ key: g.value,
163
153
  "data-test": "stash-image",
164
154
  class: ["stash-image", {
165
- "tw-rounded": t.radius === N(P).Rounded
155
+ "tw-rounded": t.radius === L(w).Rounded
166
156
  }],
167
- src: $.value
168
- }, u.value), null, 16, et));
157
+ src: g.value
158
+ }, m.value), null, 16, J));
169
159
  }
170
160
  });
171
161
  export {
172
162
  z as ImageProviders,
173
- P as ImageRadius,
174
- w as Screens,
175
- it as default
163
+ w as ImageRadius,
164
+ $ as Screens,
165
+ et as default
176
166
  };
177
167
  //# sourceMappingURL=Image.js.map
package/dist/Image.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Image.js","sources":["../src/components/Image/Image.types.ts","../src/components/Image/providers/utils.ts","../src/components/Image/providers/cloudinary.ts","../src/components/Image/providers/static.ts","../src/components/Image/providers/index.ts","../src/components/Image/Image.vue"],"sourcesContent":["// Sizes used to generate resized and optimized versions of an image.\n// Generated in `srcset`, and informed by `sizes`.\nexport const Screens = {\n xs: 160,\n sm: 338,\n md: 676,\n lg: 1352,\n xl: 2704,\n} as const;\n\nexport interface ImageSizeCondition {\n mediaQuery: string;\n screenMinWidth: number;\n size: string;\n}\n\nexport enum ImageRadius {\n None = 'none',\n Rounded = 'rounded',\n}\n\nexport type ImageRadii = `${ImageRadius}`;\n\nexport enum ImageProviders {\n Cloudinary = 'cloudinary',\n Static = 'static',\n}\n","export interface ImageModifiers {\n format?: string;\n height?: number;\n width?: number;\n [key: string]: any /* eslint-disable-line @typescript-eslint/no-explicit-any */;\n}\n\nexport type ParamFormatter = (key: string, value: string) => string;\n\nexport type ParamMapper = { [key: string]: string } | ((key: string) => string);\n\nexport interface ProviderUrlBuilder {\n keyMap?: ParamMapper;\n formatter?: ParamFormatter;\n joinWith?: string;\n valueMap?: {\n [key: string]: ParamMapper;\n };\n}\n\nfunction createMapper(map: ParamMapper) {\n return (key: string) => {\n return map[key] || key;\n };\n}\n\n/**\n * Builds the parameterized Cloudinary url\n */\nexport function buildProviderUrl({\n formatter = (key, value) => `${key}=${value}`,\n keyMap,\n joinWith = '/',\n valueMap = {},\n}: ProviderUrlBuilder = {}) {\n const keyMapper = typeof keyMap === 'function' ? keyMap : createMapper(keyMap || {});\n\n Object.keys(valueMap).forEach((valueKey) => {\n if (typeof valueMap[valueKey] !== 'function') {\n valueMap[valueKey] = createMapper(valueMap[valueKey]);\n }\n });\n\n return (modifiers: { [key: string]: string } = {}) => {\n const operations = Object.entries(modifiers).map(([key, value]) => {\n const mapper = valueMap[key];\n const newKey = keyMapper(key);\n let newVal = value;\n\n if (typeof mapper === 'function') {\n newVal = mapper(modifiers[key]);\n }\n\n return formatter(newKey, newVal);\n });\n\n return operations.join(joinWith);\n };\n}\n\n/**\n * Checks if a (sub)domain is included in a list of acceptable domains\n * @param str the (sub)domain to check\n * @param domains an array of valid domains\n */\nexport function isDomainValid(str = '', domains: string[] = []): boolean {\n const url = new URL(str);\n const host = url.host;\n\n return domains.some((domain) => {\n if (domain === host) {\n return true;\n }\n\n return domain.endsWith(`.${host}`);\n });\n}\n","import merge from 'lodash-es/merge';\n\nimport { IMAGE_PROVIDER_URLS } from '../../../constants';\nimport { buildProviderUrl, ImageModifiers } from './utils';\n\nconst BASE_URL = IMAGE_PROVIDER_URLS.CLOUDINARY;\n\nconst convertHextoRGBFormat = (value: string) => (value.startsWith('#') ? value.replace('#', 'rgb_') : value);\n\n/**\n * Parameters (option and value pairs) that can be used in the <transformations> segment of the Cloudinary transformation URL.\n * Options and their respective values are connected by an underscore (eg `w_250` for width of 250px.).\n * Multiple parameters are comma separated (eg. `w_250,h_250`).\n *\n * `keyMap` maps the option to its option prefix.\n * `valueMap` is used for grouping options using the same `keyMap` value under a 'category', allowing for easier usage and custom labelling in the component context.\n *\n * Transformation URL structure:\n * https://cloudinary.com/documentation/transformation_reference\n *\n * Transformation URL parameters (options and values):\n * https://cloudinary.com/documentation/image_transformations#transformation_url_syntax\n *\n */\nexport const operationsGenerator = buildProviderUrl({\n keyMap: {\n fit: 'c',\n width: 'w',\n height: 'h',\n format: 'f',\n quality: 'q',\n background: 'b',\n dpr: 'dpr',\n },\n valueMap: {\n fit: {\n fill: 'fill',\n inside: 'pad',\n outside: 'lpad',\n cover: 'fit',\n contain: 'scale',\n },\n format: {\n jpeg: 'jpg',\n },\n background(value: string) {\n return convertHextoRGBFormat(value);\n },\n },\n joinWith: ',',\n formatter: (key, value) => `${key}_${value}`,\n});\n\n// Note: Not configurable via Image props (for now).\nconst defaultModifiers = {\n format: 'auto',\n quality: 'auto:best',\n};\n\nexport function getImageUrl(src: string, modifiers: Partial<ImageModifiers> = {}): string {\n const mergeModifiers = merge(defaultModifiers, modifiers);\n const operations = operationsGenerator(mergeModifiers);\n\n return `${BASE_URL}/${operations}/${src}`;\n}\n","export function getImageUrl(src = ''): string {\n return src;\n}\n","import * as cloudinary from './cloudinary';\nimport * as staticProvider from './static';\n\nexport default {\n cloudinary,\n static: staticProvider,\n};\n","<script lang=\"ts\">\n export * from './Image.types';\n</script>\n\n<script setup lang=\"ts\">\n import logger from '@leaflink/snitch';\n import { computed, inject, useAttrs } from 'vue';\n\n import { StashImageProviders, StashProvideState } from '../../../types/misc';\n import { SCREEN_SIZES } from '../../constants';\n import { ImageProviders, ImageRadii, ImageRadius, ImageSizeCondition, Screens } from './Image.types';\n import providers from './providers';\n import { ImageModifiers, isDomainValid } from './providers/utils';\n\n export interface ImageProps {\n /**\n * The path to the image you want to embed.\n */\n src: string;\n\n /**\n * Native srcset attribute.\n * One or more strings separated by commas, indicating possible image sources\n * Can only be used with provider=static, otherwise it's ignored and auto-generated with `sizes` usage\n */\n srcset?: string;\n\n /**\n * For specifying responsive sizes\n */\n sizes?: string;\n\n /**\n * Where the image is served from.\n * Optional, and when provided it forces the provider used.\n *\n * The provider is otherwise inherited from the Stash config `stashOptions.images.provider`, which defaults to `cloudinary`.\n *\n * When not provided, the provider is also inferred by `isStatic`:\n * - `static` for relative/absolute paths (`img/foo.jpg` or `/static/img/bar.jpg`), or when whitelisted absolute URLs are used (included in `staticOptions.images.staticDomains`).\n */\n provider?: StashImageProviders;\n\n /**\n * For applying border radius\n */\n radius?: ImageRadii;\n\n /**\n * A custom static path the image src will be appended onto when provider=static.\n * Can be used to override the library-level default.\n */\n staticPath?: string;\n\n /**\n * TODO - https://leaflink.atlassian.net/browse/GRO-204\n * A custom function used to resolve a URL string for the image\n */\n // loader?: () => string;\n }\n\n const BREAKPOINTS = {\n md: SCREEN_SIZES.md,\n lg: SCREEN_SIZES.lg,\n };\n const stashOptions = inject<StashProvideState>('stashOptions');\n const props = withDefaults(defineProps<ImageProps>(), {\n src: '',\n srcset: undefined,\n sizes: undefined,\n staticPath: undefined,\n provider: undefined,\n radius: 'none',\n // loader: undefined, // TODO - https://leaflink.atlassian.net/browse/GRO-204\n });\n\n const attrs = computed(() => {\n const { src, ...attrs } = useAttrs();\n\n attrs.sizes = imgSizes.value;\n attrs.srcset = imgSrcset.value;\n\n return attrs;\n });\n\n const staticDomains = computed(() => stashOptions?.images?.staticDomains || []);\n\n const isAbsoluteUrl = computed(() => {\n // return true if not an absolute url\n try {\n new URL(props.src);\n return true;\n } catch (e) {\n return false;\n }\n });\n\n const isValidStaticAbsoluteUrl = computed(() => {\n return isAbsoluteUrl.value && isDomainValid(props.src, staticDomains.value);\n });\n\n const computedProvider = computed(() => props.provider || stashOptions?.images?.provider || ImageProviders.Static);\n\n const computedStaticPath = computed(() => props.staticPath || stashOptions?.staticPath);\n\n const isStatic = computed(() => computedProvider.value === ImageProviders.Static);\n\n const imgProvider = computed(() => providers[computedProvider.value]);\n\n const imgSrc = computed(() => (isStatic.value ? getProviderImage() : getProviderImage({ width: Screens.md })));\n\n const imgSizes = computed(() => (props.sizes ? getSizes() : props.sizes));\n\n const imgSrcset = computed(() => (props.sizes && !props.srcset && !isStatic.value ? getSources() : props.srcset));\n\n const parsedSizes = computed(() => {\n return props.sizes ? parseSizes(props.sizes) : [];\n });\n\n function getProviderImage(modifiers: ImageModifiers = {}) {\n if (isStatic.value && isAbsoluteUrl.value && !isValidStaticAbsoluteUrl.value) {\n // eslint-disable-next-line no-console\n logger.error(`Image: ${props.src} is not from a whitelisted domain. See \\`stashOptions.image.domains\\`.`);\n return '';\n }\n\n if (isStatic.value && isValidStaticAbsoluteUrl.value) {\n return props.src;\n }\n\n const src = isStatic.value && computedStaticPath.value ? `${computedStaticPath.value}/${props.src}` : props.src;\n\n return imgProvider.value.getImageUrl(src, modifiers);\n }\n\n function getSources() {\n return Object.values(Screens)\n .map((width) => {\n const src = getProviderImage({ width });\n\n return `${src} ${width}w`;\n })\n .join(', ');\n }\n\n function getSizes() {\n // return if using native media conditions\n if (props.sizes?.includes('(')) {\n return props.sizes;\n }\n\n return parsedSizes.value.map((v) => `${v.mediaQuery ? v.mediaQuery + ' ' : ''}${v.size}`).join(', ');\n }\n\n function parseSizes(providedSizes = '') {\n const conditions: ImageSizeCondition[] = [];\n const sizes = {\n default: '100vw',\n };\n\n // parse sizes and convert to object\n if (typeof providedSizes === 'string') {\n const definitions = providedSizes.split(/[\\s]+/).filter((size) => size);\n\n for (const entry of definitions) {\n const size = entry.split(':');\n\n if (size.length !== 2) {\n sizes['default'] = size[0].trim();\n continue;\n }\n\n sizes[size[0].trim()] = size[1].trim();\n }\n } else {\n throw new Error('`sizes` needs to be a string');\n }\n\n for (const key in sizes) {\n const screenMinWidth = parseInt(BREAKPOINTS[key] || 0);\n let size = String(sizes[key]);\n const isFluidSize = size.endsWith('vw');\n\n // convert integer to pixels\n if (!isFluidSize && /^\\d+$/.test(size)) {\n size = `${size}px`;\n }\n\n if (!isFluidSize && size.endsWith('%')) {\n throw new Error('Image: `sizes` does not support percentage values');\n }\n\n const condition = {\n mediaQuery: screenMinWidth ? `(min-width: ${screenMinWidth}px)` : '',\n screenMinWidth,\n size,\n };\n\n conditions.push(condition);\n }\n\n conditions.sort((v1, v2) => (v1.screenMinWidth > v2.screenMinWidth ? -1 : 1));\n\n return conditions;\n }\n</script>\n\n<template>\n <img\n ref=\"img\"\n :key=\"imgSrc\"\n data-test=\"stash-image\"\n class=\"stash-image\"\n :class=\"{\n 'tw-rounded': props.radius === ImageRadius.Rounded,\n }\"\n :src=\"imgSrc\"\n v-bind=\"attrs\"\n />\n</template>\n"],"names":["Screens","ImageRadius","ImageProviders","createMapper","map","key","buildProviderUrl","formatter","value","keyMap","joinWith","valueMap","keyMapper","valueKey","modifiers","mapper","newKey","newVal","isDomainValid","str","domains","host","domain","BASE_URL","IMAGE_PROVIDER_URLS","convertHextoRGBFormat","operationsGenerator","defaultModifiers","getImageUrl","src","mergeModifiers","merge","operations","providers","cloudinary","staticProvider","BREAKPOINTS","SCREEN_SIZES","stashOptions","inject","attrs","computed","useAttrs","imgSizes","imgSrcset","staticDomains","_a","isAbsoluteUrl","props","isValidStaticAbsoluteUrl","computedProvider","computedStaticPath","isStatic","imgProvider","imgSrc","getProviderImage","getSizes","getSources","parsedSizes","parseSizes","logger","width","v","providedSizes","conditions","sizes","definitions","size","entry","screenMinWidth","isFluidSize","condition","v1","v2"],"mappings":"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"}
1
+ {"version":3,"file":"Image.js","sources":["../src/components/Image/Image.types.ts","../src/components/Image/providers/utils.ts","../src/components/Image/providers/cloudinary.ts","../src/components/Image/providers/static.ts","../src/components/Image/providers/index.ts","../src/components/Image/Image.vue"],"sourcesContent":["// Sizes used to generate resized and optimized versions of an image.\n// Generated in `srcset`, and informed by `sizes`.\nexport const Screens = {\n xs: 160,\n sm: 338,\n md: 676,\n lg: 1352,\n xl: 2704,\n} as const;\n\nexport interface ImageSizeCondition {\n mediaQuery: string;\n screenMinWidth: number;\n size: string;\n}\n\nexport enum ImageRadius {\n None = 'none',\n Rounded = 'rounded',\n}\n\nexport type ImageRadii = `${ImageRadius}`;\n\nexport enum ImageProviders {\n Cloudinary = 'cloudinary',\n Static = 'static',\n}\n","export interface ImageModifiers {\n format?: string;\n height?: number;\n width?: number;\n [key: string]: any /* eslint-disable-line @typescript-eslint/no-explicit-any */;\n}\n\nexport type ParamFormatter = (key: string, value: string) => string;\n\nexport type ParamMapper = { [key: string]: string } | ((key: string) => string);\n\nexport interface ProviderUrlBuilder {\n keyMap?: ParamMapper;\n formatter?: ParamFormatter;\n joinWith?: string;\n valueMap?: {\n [key: string]: ParamMapper;\n };\n}\n\nfunction createMapper(map: ParamMapper) {\n return (key: string) => {\n return map[key] || key;\n };\n}\n\n/**\n * Builds the parameterized Cloudinary url\n */\nexport function buildProviderUrl({\n formatter = (key, value) => `${key}=${value}`,\n keyMap,\n joinWith = '/',\n valueMap = {},\n}: ProviderUrlBuilder = {}) {\n const keyMapper = typeof keyMap === 'function' ? keyMap : createMapper(keyMap || {});\n\n Object.keys(valueMap).forEach((valueKey) => {\n if (typeof valueMap[valueKey] !== 'function') {\n valueMap[valueKey] = createMapper(valueMap[valueKey]);\n }\n });\n\n return (modifiers: { [key: string]: string } = {}) => {\n const operations = Object.entries(modifiers).map(([key, value]) => {\n const mapper = valueMap[key];\n const newKey = keyMapper(key);\n let newVal = value;\n\n if (typeof mapper === 'function') {\n newVal = mapper(modifiers[key]);\n }\n\n return formatter(newKey, newVal);\n });\n\n return operations.join(joinWith);\n };\n}\n\n/**\n * Checks if a (sub)domain is included in a list of acceptable domains\n * @param str the (sub)domain to check\n * @param domains an array of valid domains\n */\nexport function isDomainValid(str = '', domains: string[] = []): boolean {\n const url = new URL(str);\n const host = url.host;\n\n return domains.some((domain) => {\n if (domain === host) {\n return true;\n }\n\n return domain.endsWith(`.${host}`);\n });\n}\n","import merge from 'lodash-es/merge';\n\nimport { IMAGE_PROVIDER_URLS } from '../../../constants';\nimport { buildProviderUrl, ImageModifiers } from './utils';\n\nconst BASE_URL = IMAGE_PROVIDER_URLS.CLOUDINARY;\n\nconst convertHextoRGBFormat = (value: string) => (value.startsWith('#') ? value.replace('#', 'rgb_') : value);\n\n/**\n * Parameters (option and value pairs) that can be used in the <transformations> segment of the Cloudinary transformation URL.\n * Options and their respective values are connected by an underscore (eg `w_250` for width of 250px.).\n * Multiple parameters are comma separated (eg. `w_250,h_250`).\n *\n * `keyMap` maps the option to its option prefix.\n * `valueMap` is used for grouping options using the same `keyMap` value under a 'category', allowing for easier usage and custom labelling in the component context.\n *\n * Transformation URL structure:\n * https://cloudinary.com/documentation/transformation_reference\n *\n * Transformation URL parameters (options and values):\n * https://cloudinary.com/documentation/image_transformations#transformation_url_syntax\n *\n */\nexport const operationsGenerator = buildProviderUrl({\n keyMap: {\n fit: 'c',\n width: 'w',\n height: 'h',\n format: 'f',\n quality: 'q',\n background: 'b',\n dpr: 'dpr',\n },\n valueMap: {\n fit: {\n fill: 'fill',\n inside: 'pad',\n outside: 'lpad',\n cover: 'fit',\n contain: 'scale',\n },\n format: {\n jpeg: 'jpg',\n },\n background(value: string) {\n return convertHextoRGBFormat(value);\n },\n },\n joinWith: ',',\n formatter: (key, value) => `${key}_${value}`,\n});\n\n// Note: Not configurable via Image props (for now).\nconst defaultModifiers = {\n format: 'auto',\n quality: 'auto:best',\n};\n\nexport function getImageUrl(src: string, modifiers: Partial<ImageModifiers> = {}): string {\n const mergeModifiers = merge(defaultModifiers, modifiers);\n const operations = operationsGenerator(mergeModifiers);\n\n return `${BASE_URL}/${operations}/${src}`;\n}\n","export function getImageUrl(src = ''): string {\n return src;\n}\n","import * as cloudinary from './cloudinary';\nimport * as staticProvider from './static';\n\nexport default {\n cloudinary,\n static: staticProvider,\n};\n","<script lang=\"ts\">\n export * from './Image.types';\n</script>\n\n<script setup lang=\"ts\">\n import { computed, inject, useAttrs } from 'vue';\n\n import { StashImageProviders, StashProvideState } from '../../../types/misc';\n import { SCREEN_SIZES } from '../../constants';\n import { ImageProviders, ImageRadii, ImageRadius, ImageSizeCondition, Screens } from './Image.types';\n import providers from './providers';\n import { ImageModifiers } from './providers/utils';\n\n export interface ImageProps {\n /**\n * The path to the image you want to embed.\n */\n src: string;\n\n /**\n * Native srcset attribute.\n * One or more strings separated by commas, indicating possible image sources\n * Can only be used with provider=static, otherwise it's ignored and auto-generated with `sizes` usage\n */\n srcset?: string;\n\n /**\n * For specifying responsive sizes\n */\n sizes?: string;\n\n /**\n * Where the image is served from.\n * If not provided, the provider will inherit from the Stash config `stashOptions.images.provider` (default: `static`).\n * - `static` for relative or absolute paths\n * - `cloudinary` for images served via Cloudinary\n */\n provider?: StashImageProviders;\n\n /**\n * For applying border radius\n */\n radius?: ImageRadii;\n\n /**\n * A custom static path the image src will be appended onto when provider=static.\n * Can be used to override the library-level default.\n */\n staticPath?: string;\n\n /**\n * TODO - https://leaflink.atlassian.net/browse/GRO-204\n * A custom function used to resolve a URL string for the image\n */\n // loader?: () => string;\n }\n\n const BREAKPOINTS = {\n md: SCREEN_SIZES.md,\n lg: SCREEN_SIZES.lg,\n };\n const stashOptions = inject<StashProvideState>('stashOptions');\n const props = withDefaults(defineProps<ImageProps>(), {\n src: '',\n srcset: undefined,\n sizes: undefined,\n staticPath: undefined,\n provider: undefined,\n radius: 'none',\n // loader: undefined, // TODO - https://leaflink.atlassian.net/browse/GRO-204\n });\n\n const attrs = computed(() => {\n const { src, ...attrs } = useAttrs();\n\n attrs.sizes = imgSizes.value;\n attrs.srcset = imgSrcset.value;\n\n return attrs;\n });\n\n const isAbsoluteUrl = computed(() => {\n // return true if not an absolute url\n try {\n new URL(props.src);\n return true;\n } catch (e) {\n return false;\n }\n });\n\n const computedProvider = computed(() => props.provider || stashOptions?.images?.provider || ImageProviders.Static);\n\n const computedStaticPath = computed(() => props.staticPath ?? stashOptions?.staticPath);\n\n const isStatic = computed(() => computedProvider.value === ImageProviders.Static);\n\n const imgProvider = computed(() => providers[computedProvider.value]);\n\n const imgSrc = computed(() => (isStatic.value ? getProviderImage() : getProviderImage({ width: Screens.md })));\n\n const imgSizes = computed(() => (props.sizes ? getSizes() : props.sizes));\n\n const imgSrcset = computed(() => (props.sizes && !props.srcset && !isStatic.value ? getSources() : props.srcset));\n\n const parsedSizes = computed(() => {\n return props.sizes ? parseSizes(props.sizes) : [];\n });\n\n function getProviderImage(modifiers: ImageModifiers = {}) {\n if (isStatic.value && isAbsoluteUrl.value) {\n return props.src;\n }\n\n const src = isStatic.value && computedStaticPath.value ? `${computedStaticPath.value}/${props.src}` : props.src;\n\n return imgProvider.value.getImageUrl(src, modifiers);\n }\n\n function getSources() {\n return Object.values(Screens)\n .map((width) => {\n const src = getProviderImage({ width });\n\n return `${src} ${width}w`;\n })\n .join(', ');\n }\n\n function getSizes() {\n // return if using native media conditions\n if (props.sizes?.includes('(')) {\n return props.sizes;\n }\n\n return parsedSizes.value.map((v) => `${v.mediaQuery ? v.mediaQuery + ' ' : ''}${v.size}`).join(', ');\n }\n\n function parseSizes(providedSizes = '') {\n const conditions: ImageSizeCondition[] = [];\n const sizes = {\n default: '100vw',\n };\n\n // parse sizes and convert to object\n if (typeof providedSizes === 'string') {\n const definitions = providedSizes.split(/[\\s]+/).filter((size) => size);\n\n for (const entry of definitions) {\n const size = entry.split(':');\n\n if (size.length !== 2) {\n sizes['default'] = size[0].trim();\n continue;\n }\n\n sizes[size[0].trim()] = size[1].trim();\n }\n } else {\n throw new Error('`sizes` needs to be a string');\n }\n\n for (const key in sizes) {\n const screenMinWidth = parseInt(BREAKPOINTS[key] || 0);\n let size = String(sizes[key]);\n const isFluidSize = size.endsWith('vw');\n\n // convert integer to pixels\n if (!isFluidSize && /^\\d+$/.test(size)) {\n size = `${size}px`;\n }\n\n if (!isFluidSize && size.endsWith('%')) {\n throw new Error('Image: `sizes` does not support percentage values');\n }\n\n const condition = {\n mediaQuery: screenMinWidth ? `(min-width: ${screenMinWidth}px)` : '',\n screenMinWidth,\n size,\n };\n\n conditions.push(condition);\n }\n\n conditions.sort((v1, v2) => (v1.screenMinWidth > v2.screenMinWidth ? -1 : 1));\n\n return conditions;\n }\n</script>\n\n<template>\n <img\n ref=\"img\"\n :key=\"imgSrc\"\n data-test=\"stash-image\"\n class=\"stash-image\"\n :class=\"{\n 'tw-rounded': props.radius === ImageRadius.Rounded,\n }\"\n :src=\"imgSrc\"\n v-bind=\"attrs\"\n />\n</template>\n"],"names":["Screens","ImageRadius","ImageProviders","createMapper","map","key","buildProviderUrl","formatter","value","keyMap","joinWith","valueMap","keyMapper","valueKey","modifiers","mapper","newKey","newVal","BASE_URL","IMAGE_PROVIDER_URLS","convertHextoRGBFormat","operationsGenerator","defaultModifiers","getImageUrl","src","mergeModifiers","merge","operations","providers","cloudinary","staticProvider","BREAKPOINTS","SCREEN_SIZES","stashOptions","inject","attrs","computed","useAttrs","imgSizes","imgSrcset","isAbsoluteUrl","props","computedProvider","_a","computedStaticPath","isStatic","imgProvider","imgSrc","getProviderImage","getSizes","getSources","parsedSizes","parseSizes","width","v","providedSizes","conditions","sizes","definitions","size","entry","screenMinWidth","isFluidSize","condition","v1","v2"],"mappings":"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"}
@@ -68,12 +68,9 @@ export declare interface ImageProps {
68
68
  sizes?: string;
69
69
  /**
70
70
  * Where the image is served from.
71
- * Optional, and when provided it forces the provider used.
72
- *
73
- * The provider is otherwise inherited from the Stash config `stashOptions.images.provider`, which defaults to `cloudinary`.
74
- *
75
- * When not provided, the provider is also inferred by `isStatic`:
76
- * - `static` for relative/absolute paths (`img/foo.jpg` or `/static/img/bar.jpg`), or when whitelisted absolute URLs are used (included in `staticOptions.images.staticDomains`).
71
+ * If not provided, the provider will inherit from the Stash config `stashOptions.images.provider` (default: `static`).
72
+ * - `static` for relative or absolute paths
73
+ * - `cloudinary` for images served via Cloudinary
77
74
  */
78
75
  provider?: StashImageProviders;
79
76
  /**
package/dist/ListItem.js CHANGED
@@ -4,12 +4,12 @@ import { _ as r } from "./_plugin-vue_export-helper-dad06003.js";
4
4
  import "@leaflink/snitch";
5
5
  import "lodash-es/uniqueId";
6
6
  import "./Checkbox.vue_used_vue_type_style_index_0_lang.module-fa8d9c06.js";
7
- const f = "_item_1v8cf_2", _ = "_checkbox_1v8cf_56", h = {
8
- item: f,
9
- "is-selectable": "_is-selectable_1v8cf_41",
10
- "not-actionable": "_not-actionable_1v8cf_46",
7
+ const k = "_item_12k6c_2", _ = "_checkbox_12k6c_56", f = {
8
+ item: k,
9
+ "is-selectable": "_is-selectable_12k6c_41",
10
+ "not-actionable": "_not-actionable_12k6c_46",
11
11
  checkbox: _
12
- }, k = {
12
+ }, h = {
13
13
  name: "ll-list-item",
14
14
  components: {
15
15
  "ll-checkbox": a
@@ -88,9 +88,9 @@ function u(e, y, t, B, x, o) {
88
88
  ], 2);
89
89
  }
90
90
  const p = {
91
- $style: h
92
- }, A = /* @__PURE__ */ r(k, [["render", u], ["__cssModules", p]]);
91
+ $style: f
92
+ }, M = /* @__PURE__ */ r(h, [["render", u], ["__cssModules", p]]);
93
93
  export {
94
- A as default
94
+ M as default
95
95
  };
96
96
  //# sourceMappingURL=ListItem.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ListItem.js","sources":["../src/components/ListItem/ListItem.vue"],"sourcesContent":["<script>\n import Checkbox from '../Checkbox/Checkbox.vue';\n\n export default {\n name: 'll-list-item',\n\n components: {\n 'll-checkbox': Checkbox,\n },\n\n props: {\n /**\n * The item to be selected\n */\n item: {\n type: Object,\n default: () => ({}),\n },\n\n /**\n * Whether this row can be selected.\n */\n isSelectable: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Whether this row's checkbox should be indeterminite\n */\n isIndeterminate: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Whether this row has an actions column or not. By default list items will\n * be styled to include actions. Use `not-actionable` to restyle a row that\n * has no actions.\n */\n notActionable: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Whether this row is selected.\n */\n selected: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Disables the checkbox\n */\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n\n emits: ['select'],\n\n methods: {\n /**\n * @param {boolean} value emit change event when item is selected\n */\n onSelect(value) {\n this.$emit('select', { item: this.item, value });\n },\n },\n };\n</script>\n\n<template>\n <li\n class=\"shadow-low\"\n :class=\"[$style.item, { [$style['is-selectable']]: isSelectable, [$style['not-actionable']]: notActionable }]\"\n >\n <ll-checkbox\n v-if=\"isSelectable\"\n data-test=\"checkbox|select-item\"\n :checked=\"selected\"\n :class=\"$style.checkbox\"\n :disabled=\"disabled || null\"\n :indeterminate=\"isIndeterminate\"\n @update:checked=\"onSelect\"\n />\n <slot></slot>\n </li>\n</template>\n\n<style module>\n .item {\n background: var(--color-white);\n border-radius: theme('borderRadius.DEFAULT');\n column-gap: var(--grid-gutter);\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n margin-bottom: theme('spacing.6');\n padding: theme('spacing.3');\n padding-top: theme('spacing.12');\n position: relative;\n row-gap: var(--grid-gutter);\n }\n\n @media screen('md') {\n .item {\n grid-template-columns: repeat(8, 1fr);\n }\n }\n\n @media screen('lg') {\n .item {\n align-items: center;\n border-bottom: 1px solid var(--color-ice-200);\n border-radius: 0;\n box-shadow: none;\n grid-template-columns: repeat(12, 1fr);\n margin-bottom: 0;\n padding: theme('spacing.6');\n row-gap: 0;\n }\n\n .item:last-child {\n border: 0;\n border-bottom-left-radius: theme('borderRadius.DEFAULT');\n border-bottom-right-radius: theme('borderRadius.DEFAULT');\n }\n }\n\n @media screen('lg') {\n .is-selectable {\n grid-template-columns: theme('spacing[1.5]') repeat(12, 1fr);\n }\n }\n\n .not-actionable {\n padding-top: theme('spacing.3');\n }\n\n @media screen('lg') {\n .not-actionable {\n padding-top: theme('spacing.6');\n }\n }\n\n .checkbox {\n left: theme('spacing.3');\n position: absolute !important;\n top: 0;\n }\n\n @media screen('lg') {\n .checkbox {\n left: 0;\n position: relative !important;\n }\n\n .checkbox label {\n padding: 10px;\n }\n\n .checkbox label::before,\n .checkbox input:checked + label::after {\n top: 0;\n }\n }\n</style>\n"],"names":["_sfc_main","Checkbox","value","_createElementBlock","_normalizeClass","_ctx","$props","_createBlock","_component_ll_checkbox","$options","_renderSlot"],"mappings":";;;;;;;;;;;GAGOA,IAAU;AAAA,EACb,MAAM;AAAA,EAEN,YAAY;AAAA,IACV,eAAeC;AAAA,EAChB;AAAA,EAED,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,SAAS,OAAO,CAAA;AAAA,IACjB;AAAA;AAAA;AAAA;AAAA,IAKD,cAAc;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA,IAKD,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOD,eAAe;AAAA,MACb,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA,IAKD,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA,IAKD,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,EACF;AAAA,EAED,OAAO,CAAC,QAAQ;AAAA,EAEhB,SAAS;AAAA;AAAA;AAAA;AAAA,IAIP,SAASC,GAAO;AACd,WAAK,MAAM,UAAU,EAAE,MAAM,KAAK,MAAM,OAAAA,EAAI,CAAG;AAAA,IAChD;AAAA,EACF;;;;cAKHC,EAcK,MAAA;AAAA,IAbH,OAAMC,EAAA,CAAA,cACG,CAAAC,EAAA,OAAO,MAAS,EAAA,CAAAA,EAAA,OAA0B,eAAA,CAAA,GAAAC,EAAA,cAAe,CAAAD,EAAA,2BAA2BC,EAAa,cAAA,CAAA,CAAA,CAAA;AAAA;IAGlGA,EAAY,qBADpBC,EAQEC,GAAA;AAAA;MANA,aAAU;AAAA,MACT,SAASF,EAAQ;AAAA,MACjB,OAAKF,EAAEC,EAAM,OAAC,QAAQ;AAAA,MACtB,UAAUC,EAAQ,YAAA;AAAA,MAClB,eAAeA,EAAe;AAAA,MAC9B,oBAAgBG,EAAQ;AAAA;IAE3BC,EAAaL,EAAA,QAAA,SAAA;AAAA;;;;;"}
1
+ {"version":3,"file":"ListItem.js","sources":["../src/components/ListItem/ListItem.vue"],"sourcesContent":["<script>\n import Checkbox from '../Checkbox/Checkbox.vue';\n\n export default {\n name: 'll-list-item',\n\n components: {\n 'll-checkbox': Checkbox,\n },\n\n props: {\n /**\n * The item to be selected\n */\n item: {\n type: Object,\n default: () => ({}),\n },\n\n /**\n * Whether this row can be selected.\n */\n isSelectable: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Whether this row's checkbox should be indeterminite\n */\n isIndeterminate: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Whether this row has an actions column or not. By default list items will\n * be styled to include actions. Use `not-actionable` to restyle a row that\n * has no actions.\n */\n notActionable: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Whether this row is selected.\n */\n selected: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Disables the checkbox\n */\n disabled: {\n type: Boolean,\n default: false,\n },\n },\n\n emits: ['select'],\n\n methods: {\n /**\n * @param {boolean} value emit change event when item is selected\n */\n onSelect(value) {\n this.$emit('select', { item: this.item, value });\n },\n },\n };\n</script>\n\n<template>\n <li\n class=\"shadow-low\"\n :class=\"[$style.item, { [$style['is-selectable']]: isSelectable, [$style['not-actionable']]: notActionable }]\"\n >\n <ll-checkbox\n v-if=\"isSelectable\"\n data-test=\"checkbox|select-item\"\n :checked=\"selected\"\n :class=\"$style.checkbox\"\n :disabled=\"disabled || null\"\n :indeterminate=\"isIndeterminate\"\n @update:checked=\"onSelect\"\n />\n <slot></slot>\n </li>\n</template>\n\n<style module>\n .item {\n background: var(--color-white);\n border-radius: theme('borderRadius.DEFAULT');\n column-gap: var(--grid-gutter);\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n margin-bottom: theme('spacing.6');\n padding: theme('spacing.3');\n padding-top: theme('spacing.12');\n position: relative;\n row-gap: var(--grid-gutter);\n }\n\n @media screen('md') {\n .item {\n grid-template-columns: repeat(8, 1fr);\n }\n }\n\n @media screen('lg') {\n .item {\n align-items: center;\n border-bottom: 1px solid var(--color-ice-200);\n border-radius: 0;\n box-shadow: none;\n grid-template-columns: repeat(12, 1fr);\n margin-bottom: 0;\n padding: theme('spacing.6');\n row-gap: 0;\n }\n\n .item:last-child {\n border: 0;\n border-bottom-left-radius: theme('borderRadius.DEFAULT');\n border-bottom-right-radius: theme('borderRadius.DEFAULT');\n }\n }\n\n @media screen('lg') {\n .is-selectable {\n grid-template-columns: theme('spacing[1.5]') repeat(12, 1fr);\n }\n }\n\n .not-actionable {\n padding-top: theme('spacing.3');\n }\n\n @media screen('lg') {\n .not-actionable {\n padding-top: theme('spacing.6');\n }\n }\n\n .checkbox {\n left: theme('spacing.3');\n position: absolute !important;\n top: 0;\n }\n\n @media screen('lg') {\n .checkbox {\n left: 0;\n position: relative !important;\n }\n\n .checkbox label {\n padding: 10px;\n }\n }\n</style>\n"],"names":["_sfc_main","Checkbox","value","_createElementBlock","_normalizeClass","_ctx","$props","_createBlock","_component_ll_checkbox","$options","_renderSlot"],"mappings":";;;;;;;;;;;GAGOA,IAAU;AAAA,EACb,MAAM;AAAA,EAEN,YAAY;AAAA,IACV,eAAeC;AAAA,EAChB;AAAA,EAED,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,SAAS,OAAO,CAAA;AAAA,IACjB;AAAA;AAAA;AAAA;AAAA,IAKD,cAAc;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA,IAKD,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOD,eAAe;AAAA,MACb,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA,IAKD,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA,IAKD,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,EACF;AAAA,EAED,OAAO,CAAC,QAAQ;AAAA,EAEhB,SAAS;AAAA;AAAA;AAAA;AAAA,IAIP,SAASC,GAAO;AACd,WAAK,MAAM,UAAU,EAAE,MAAM,KAAK,MAAM,OAAAA,EAAI,CAAG;AAAA,IAChD;AAAA,EACF;;;;cAKHC,EAcK,MAAA;AAAA,IAbH,OAAMC,EAAA,CAAA,cACG,CAAAC,EAAA,OAAO,MAAS,EAAA,CAAAA,EAAA,OAA0B,eAAA,CAAA,GAAAC,EAAA,cAAe,CAAAD,EAAA,2BAA2BC,EAAa,cAAA,CAAA,CAAA,CAAA;AAAA;IAGlGA,EAAY,qBADpBC,EAQEC,GAAA;AAAA;MANA,aAAU;AAAA,MACT,SAASF,EAAQ;AAAA,MACjB,OAAKF,EAAEC,EAAM,OAAC,QAAQ;AAAA,MACtB,UAAUC,EAAQ,YAAA;AAAA,MAClB,eAAeA,EAAe;AAAA,MAC9B,oBAAgBG,EAAQ;AAAA;IAE3BC,EAAaL,EAAA,QAAA,SAAA;AAAA;;;;;"}