@lovince/icons 1.1.1 → 1.2.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
@@ -10,14 +10,16 @@ bun add @lovince/icons
10
10
 
11
11
  No runtime dependencies. Vue is an optional peer, needed only for the Vue layer.
12
12
 
13
- ## Not another icon collection
13
+ ## What this is for
14
14
 
15
- Competing on icon count is a losing game. This competes on what generic sets
16
- don't do:
15
+ Lucide, Heroicons and Material Symbols are excellent, and this does not try to
16
+ out-draw them — 47 icons against Lucide's 2,000 is not a contest. It exists to
17
+ do the things a general-purpose set is not trying to do:
17
18
 
18
19
  | | |
19
20
  |---|---|
20
21
  | **One geometry, three variants** | Outline, duotone and filled are the same paths at different fill strengths — so a variant change is an animatable value, not a swap |
22
+ | **Any icon morphs into any other** | Not curated pairs — `home` into `settings`, `search` into `spark`. Arbitrary geometry, no hand-alignment |
21
23
  | **Transitions, not swaps** | Menu ⇄ Close, Plus ⇄ Close, and a tick that draws on. Continuity is the point |
22
24
  | **Hit area separated from icon size** | An 18px icon still gets a 44px target. The most common icon-button mistake, invisible until someone taps it |
23
25
  | **Journey step states** | `○ → ◉ → ✓` as one shape, for onboarding progress |
@@ -111,9 +113,46 @@ control moves as one object:
111
113
  </button>
112
114
  ```
113
115
 
116
+ ## Morphing
117
+
118
+ Libraries that morph icons do it by hand: a menu and a close are *drawn* as the
119
+ same three lines so CSS can rotate one into the other. That works for a handful
120
+ of curated pairs and not at all for the rest.
121
+
122
+ This morphs arbitrary geometry.
123
+
124
+ ```vue
125
+ <LvMorphIcon :name="current" :size="28" />
126
+ ```
127
+
128
+ Change `name` and the icon transforms into the new one — any icon, any other
129
+ icon, with no pre-alignment.
130
+
131
+ ```ts
132
+ import { planMorph, canMorph } from '@lovince/icons'
133
+
134
+ const plan = planMorph(paths.home, paths.settings)
135
+ plan?.at(0.5) // the geometry halfway between them
136
+ ```
137
+
138
+ **How it works.** Both icons are sampled into equal point counts using the
139
+ browser's own geometry engine (`getPointAtLength`), then interpolated. Using
140
+ the browser rather than a hand-written path parser means arcs, cubics,
141
+ quadratics and every shorthand come for free, and the sampling cannot drift
142
+ from how the path actually renders.
143
+
144
+ Sub-paths are padded on both sides, so a five-path icon can morph into a
145
+ two-path icon: the surplus collapses to a point instead of vanishing. Point
146
+ rings are rotated to their nearest alignment first, which is what stops the
147
+ shape visibly unwinding mid-morph.
148
+
149
+ Where no geometry engine exists — a server, an old browser, reduced motion —
150
+ `canMorph()` reports `false` and the component swaps instantly. The end state
151
+ is identical either way.
152
+
114
153
  ## Icon set
115
154
 
116
- 52 icons across five groups — `navigation`, `journey`, `status`, `onboarding`,
155
+ 47 icons across five groups — `navigation`, `journey`, `status`, `onboarding`,
117
156
  `interface`.
118
157
 
119
158
  ```ts
@@ -150,6 +189,37 @@ paths.js 2.0 KB gzip geometry only
150
189
  style.css 2.0 KB gzip animated components only
151
190
  ```
152
191
 
192
+ ## Prior art and credits
193
+
194
+ This set stands on conventions established by others, and it is worth naming
195
+ them.
196
+
197
+ **[Lucide](https://lucide.dev)** (ISC) — the design language here follows
198
+ Lucide's published guidelines: a 24×24 canvas, 2px centred stroke, round caps
199
+ and joins. The `absoluteStrokeWidth` prop is Lucide's name for that behaviour
200
+ and is kept deliberately, because developers already know it.
201
+
202
+ **[Material Symbols](https://fonts.google.com/icons)** (Apache-2.0) — the idea
203
+ of an icon varying continuously along axes such as fill and weight, rather than
204
+ shipping a separate file per state, comes from Material's variable font work.
205
+
206
+ **[Heroicons](https://heroicons.com)** (MIT) — for the outline/solid pairing
207
+ that this generalises into a single fill value.
208
+
209
+ ### On geometry overlap
210
+
211
+ Every path here was authored by hand rather than copied. That said, this set
212
+ was diffed against all 2,025 Lucide icons, and **21 of its 126 paths are
213
+ identical** — all of them primitive: straight lines, dots, and a chevron.
214
+
215
+ A horizontal line across a 24-unit grid has one sensible form; so does a plus,
216
+ a minus, and `M12 8h.01` for a dot. Those matches are convergence, not
217
+ authorship. No multi-curve icon matched. The comparison is reproducible if you
218
+ want to run it yourself.
219
+
220
+ Universal shapes — a house for home, a magnifier for search, three bars for a
221
+ menu — are shared visual vocabulary and belong to no one.
222
+
153
223
  ## License
154
224
 
155
225
  MIT
@@ -0,0 +1,28 @@
1
+ import { IconName } from './paths';
2
+ import { IconFlip } from './core/props';
3
+ type __VLS_Props = {
4
+ /** Change this and the icon morphs into the new one. Any icon, any other icon. */
5
+ name: IconName;
6
+ size?: number | string;
7
+ strokeWidth?: number | string;
8
+ absoluteStrokeWidth?: boolean;
9
+ flip?: IconFlip;
10
+ rotate?: number | string;
11
+ label?: string;
12
+ duration?: number;
13
+ /** Points sampled per sub-path. Higher is smoother and slower to prepare. */
14
+ resolution?: number;
15
+ };
16
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
17
+ morphed: (args_0: "arrowRight" | "arrowLeft" | "arrowUp" | "arrowDown" | "chevronRight" | "chevronLeft" | "chevronUp" | "chevronDown" | "close" | "menu" | "external" | "start" | "skip" | "complete" | "target" | "spark" | "pause" | "restart" | "success" | "warning" | "info" | "error" | "welcome" | "discover" | "click" | "swipe" | "drag" | "scroll" | "tip" | "help" | "shortcut" | "newFeature" | "home" | "search" | "install" | "book" | "code" | "palette" | "shield" | "accessibility" | "sun" | "moon" | "monitor" | "plus" | "minus" | "copy" | "settings") => any;
18
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
19
+ onMorphed?: ((args_0: "arrowRight" | "arrowLeft" | "arrowUp" | "arrowDown" | "chevronRight" | "chevronLeft" | "chevronUp" | "chevronDown" | "close" | "menu" | "external" | "start" | "skip" | "complete" | "target" | "spark" | "pause" | "restart" | "success" | "warning" | "info" | "error" | "welcome" | "discover" | "click" | "swipe" | "drag" | "scroll" | "tip" | "help" | "shortcut" | "newFeature" | "home" | "search" | "install" | "book" | "code" | "palette" | "shield" | "accessibility" | "sun" | "moon" | "monitor" | "plus" | "minus" | "copy" | "settings") => any) | undefined;
20
+ }>, {
21
+ size: number | string;
22
+ strokeWidth: number | string;
23
+ absoluteStrokeWidth: boolean;
24
+ duration: number;
25
+ resolution: number;
26
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
27
+ declare const _default: typeof __VLS_export;
28
+ export default _default;
@@ -10,8 +10,8 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {
10
10
  size: number | string;
11
11
  strokeWidth: number | string;
12
12
  absoluteStrokeWidth: boolean;
13
- open: boolean;
14
13
  duration: number;
14
+ open: boolean;
15
15
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
16
16
  declare const _default: typeof __VLS_export;
17
17
  export default _default;
@@ -10,8 +10,8 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {
10
10
  size: number | string;
11
11
  strokeWidth: number | string;
12
12
  absoluteStrokeWidth: boolean;
13
- open: boolean;
14
13
  duration: number;
14
+ open: boolean;
15
15
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
16
16
  declare const _default: typeof __VLS_export;
17
17
  export default _default;
@@ -0,0 +1,50 @@
1
+ export interface Point {
2
+ readonly x: number;
3
+ readonly y: number;
4
+ }
5
+ /**
6
+ * Morphing between *arbitrary* icons.
7
+ *
8
+ * Icon libraries that morph do it by hand: a menu and a close are drawn as the
9
+ * same three lines so CSS can rotate them. That works for a handful of curated
10
+ * pairs and not at all for the other 2,000 combinations.
11
+ *
12
+ * This samples any two paths into equal point counts and interpolates between
13
+ * them, so *any* icon can become *any* other — `home` into `settings`, `search`
14
+ * into `spark` — with no hand-alignment.
15
+ *
16
+ * The sampling uses the browser's own geometry engine (`getPointAtLength`)
17
+ * rather than a hand-written path parser. That is the whole trick: arcs,
18
+ * cubics, quadratics and every shorthand come for free and cannot drift from
19
+ * how the browser actually renders them.
20
+ *
21
+ * Where that engine is unavailable — a server, an older environment — every
22
+ * function returns `null` and callers swap instantly instead.
23
+ */
24
+ export declare const canMorph: () => boolean;
25
+ /** Samples one path into `count` points spaced evenly along its length. */
26
+ export declare const samplePath: (d: string, count: number) => Point[] | null;
27
+ /**
28
+ * Samples a whole icon. Sub-paths are padded to the same count on both sides so
29
+ * a three-path icon can morph into a one-path icon: the surplus collapses to a
30
+ * point rather than being dropped, which keeps the motion continuous.
31
+ */
32
+ export declare const sampleIcon: (shapes: readonly string[], perPath: number) => Point[][] | null;
33
+ /**
34
+ * Rotates the target ring so its start point is nearest the source's. Without
35
+ * this the shape visibly unwinds during the morph, which reads as a glitch
36
+ * rather than a transformation.
37
+ */
38
+ export declare const align: (from: readonly Point[], to: readonly Point[]) => Point[];
39
+ export declare const lerp: (a: number, b: number, t: number) => number;
40
+ export interface MorphPlan {
41
+ readonly from: Point[][];
42
+ readonly to: Point[][];
43
+ /** `at(0)` is the source icon, `at(1)` the target. */
44
+ readonly at: (progress: number) => string[];
45
+ }
46
+ /**
47
+ * Prepares a reusable interpolation between two icons. Sampling is the
48
+ * expensive part, so it happens once here rather than on every frame.
49
+ */
50
+ export declare const planMorph: (from: readonly string[], to: readonly string[], perPath?: number) => MorphPlan | null;
package/dist/index.d.ts CHANGED
@@ -8,5 +8,6 @@ export { renderIcon, createIcon, iconDataUri, type RenderOptions } from './rende
8
8
  export { defineIconElement, optionsFromAttributes, resolveElementName, type LvIconElement, } from './element';
9
9
  export { CANVAS, DEFAULT_SIZE, DEFAULT_STROKE, resolveGeometry, resolveStroke, resolveTransform, resolveFill, type IconFlip, type IconGeometry, } from './core/props';
10
10
  export { CONTEXT, VARIANT_FILL, STATE_FILL, STATE_OPACITY, opticalStroke, resolveContext, resolveVariantFill, type ContextPreset, type IconContext, type IconState, type IconVariant, } from './core/variants';
11
+ export { align, canMorph, lerp, planMorph, sampleIcon, samplePath, type MorphPlan, type Point, } from './core/morph';
11
12
  export { createTimeline, journeyChoreography, type Cue, type CueInput, type Timeline, } from './core/choreography';
12
13
  export { DURATION, EASE, cssDuration, prefersReducedMotion, resolveDuration, } from './core/motion';
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { iconGroups as e, iconNames as t, isIconName as n, paths as r } from "./paths.js";
2
- import { _ as i, a, c as o, d as s, f as c, g as l, h as u, i as d, l as f, m as p, n as m, o as h, p as g, r as _, s as v, t as y, u as b, v as x, y as S } from "./motion-72rOKpWt.js";
2
+ import { C as i, S as a, T as o, _ as s, a as c, b as l, c as u, d, f, g as p, h as m, i as h, l as g, m as _, n as v, o as y, p as b, r as x, s as S, t as C, u as w, v as T, w as E, x as D, y as O } from "./motion-CBQXeIyE.js";
3
3
  //#region src/render.ts
4
- var C = "http://www.w3.org/2000/svg", w = (e) => e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;"), T = (e, t) => {
5
- let n = i(t), a = l(t.fill), o = t.label == null || t.label.length === 0, s = {
6
- xmlns: C,
4
+ var k = "http://www.w3.org/2000/svg", A = (e) => e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;"), j = (e, t) => {
5
+ let n = i(t), o = a(t.fill), s = t.label == null || t.label.length === 0, c = {
6
+ xmlns: k,
7
7
  class: t.class ?? "lv-icon",
8
8
  width: String(n.size),
9
9
  height: String(n.size),
@@ -14,29 +14,29 @@ var C = "http://www.w3.org/2000/svg", w = (e) => e.replace(/&/g, "&amp;").replac
14
14
  "stroke-linecap": "round",
15
15
  "stroke-linejoin": "round"
16
16
  };
17
- return o ? s["aria-hidden"] = "true" : (s.role = "img", s["aria-label"] = t.label), {
18
- attrs: s,
17
+ return s ? c["aria-hidden"] = "true" : (c.role = "img", c["aria-label"] = t.label), {
18
+ attrs: c,
19
19
  shapes: r[e] ?? [],
20
20
  transform: n.transform,
21
- fill: a
21
+ fill: o
22
22
  };
23
- }, E = (e, t = {}) => {
24
- let { attrs: n, shapes: r, transform: i, fill: a } = T(e, t), o = Object.entries(n).map(([e, t]) => `${e}="${w(t)}"`).join(" "), s = a > 0 ? ` fill="currentColor" fill-opacity="${a}"` : "", c = r.map((e) => `<path d="${w(e)}"${s}/>`).join("");
25
- return `<svg ${o}>${i === void 0 ? c : `<g transform="${w(i)}">${c}</g>`}</svg>`;
26
- }, D = (e, t = {}) => {
23
+ }, M = (e, t = {}) => {
24
+ let { attrs: n, shapes: r, transform: i, fill: a } = j(e, t), o = Object.entries(n).map(([e, t]) => `${e}="${A(t)}"`).join(" "), s = a > 0 ? ` fill="currentColor" fill-opacity="${a}"` : "", c = r.map((e) => `<path d="${A(e)}"${s}/>`).join("");
25
+ return `<svg ${o}>${i === void 0 ? c : `<g transform="${A(i)}">${c}</g>`}</svg>`;
26
+ }, N = (e, t = {}) => {
27
27
  if (typeof document > "u") return null;
28
- let { attrs: n, shapes: r, transform: i, fill: a } = T(e, t), o = document.createElementNS(C, "svg");
28
+ let { attrs: n, shapes: r, transform: i, fill: a } = j(e, t), o = document.createElementNS(k, "svg");
29
29
  for (let [e, t] of Object.entries(n)) o.setAttribute(e, t);
30
30
  let s = i === void 0 ? o : (() => {
31
- let e = document.createElementNS(C, "g");
31
+ let e = document.createElementNS(k, "g");
32
32
  return e.setAttribute("transform", i), o.appendChild(e), e;
33
33
  })();
34
34
  for (let e of r) {
35
- let t = document.createElementNS(C, "path");
35
+ let t = document.createElementNS(k, "path");
36
36
  t.setAttribute("d", e), a > 0 && (t.setAttribute("fill", "currentColor"), t.setAttribute("fill-opacity", String(a))), s.appendChild(t);
37
37
  }
38
38
  return o;
39
- }, O = (e, t = {}) => `data:image/svg+xml,${encodeURIComponent(E(e, t))}`, k = [
39
+ }, P = (e, t = {}) => `data:image/svg+xml,${encodeURIComponent(M(e, t))}`, F = [
40
40
  "name",
41
41
  "size",
42
42
  "stroke-width",
@@ -45,30 +45,30 @@ var C = "http://www.w3.org/2000/svg", w = (e) => e.replace(/&/g, "&amp;").replac
45
45
  "rotate",
46
46
  "flip",
47
47
  "label"
48
- ], A = (e) => e.replace(/-([a-z])/g, (e, t) => t.toUpperCase()), j = (e) => {
48
+ ], I = (e) => e.replace(/-([a-z])/g, (e, t) => t.toUpperCase()), L = (e) => {
49
49
  if (e == null) return null;
50
- let t = A(e.trim());
50
+ let t = I(e.trim());
51
51
  return n(t) ? t : null;
52
- }, M = (e, t) => {
52
+ }, R = (e, t) => {
53
53
  if (e == null) return t;
54
54
  let n = Number.parseFloat(e);
55
55
  return Number.isFinite(n) ? n : t;
56
- }, N = (e, t) => {
56
+ }, z = (e, t) => {
57
57
  let n = e("flip"), r = e("label");
58
58
  return {
59
- size: M(e("size"), 24),
60
- strokeWidth: M(e("stroke-width"), 2),
59
+ size: R(e("size"), 24),
60
+ strokeWidth: R(e("stroke-width"), 2),
61
61
  absoluteStrokeWidth: t("absolute-stroke-width"),
62
- fill: M(e("fill"), 0),
63
- rotate: M(e("rotate"), 0),
62
+ fill: R(e("fill"), 0),
63
+ rotate: R(e("rotate"), 0),
64
64
  ...n === "horizontal" || n === "vertical" || n === "both" ? { flip: n } : {},
65
65
  ...r == null ? {} : { label: r }
66
66
  };
67
- }, P = (e = "lv-icon") => {
67
+ }, B = (e = "lv-icon") => {
68
68
  if (typeof window > "u" || typeof customElements > "u" || typeof HTMLElement > "u" || customElements.get(e) !== void 0) return;
69
69
  class t extends HTMLElement {
70
70
  static get observedAttributes() {
71
- return k;
71
+ return F;
72
72
  }
73
73
  connectedCallback() {
74
74
  this.render();
@@ -77,16 +77,16 @@ var C = "http://www.w3.org/2000/svg", w = (e) => e.replace(/&/g, "&amp;").replac
77
77
  this.isConnected && this.render();
78
78
  }
79
79
  render() {
80
- let e = j(this.getAttribute("name"));
80
+ let e = L(this.getAttribute("name"));
81
81
  if (this.replaceChildren(), e === null) return;
82
- let t = D(e, N((e) => this.getAttribute(e), (e) => this.hasAttribute(e)));
82
+ let t = N(e, z((e) => this.getAttribute(e), (e) => this.hasAttribute(e)));
83
83
  t !== null && this.appendChild(t);
84
84
  }
85
85
  }
86
86
  customElements.define(e, t);
87
- }, F = (e) => e < .5 ? 4 * e * e * e : 1 - (-2 * e + 2) ** 3 / 2, I = () => {
87
+ }, V = (e) => e < .5 ? 4 * e * e * e : 1 - (-2 * e + 2) ** 3 / 2, H = () => {
88
88
  let e = [], t = 0, n = 0, r = !1, i = (n) => {
89
- let r = n.duration ?? y.state, i = Math.max(0, t + (n.offset ?? 0));
89
+ let r = n.duration ?? C.state, i = Math.max(0, t + (n.offset ?? 0));
90
90
  e.push({
91
91
  name: n.name,
92
92
  at: i,
@@ -94,23 +94,23 @@ var C = "http://www.w3.org/2000/svg", w = (e) => e.replace(/&/g, "&amp;").replac
94
94
  run: n.run,
95
95
  ...n.onComplete === void 0 ? {} : { onComplete: n.onComplete }
96
96
  }), t = i + r;
97
- }, o = {
98
- add: (e) => (i(e), o),
99
- stagger: (e, n = y.micro / 2) => {
97
+ }, a = {
98
+ add: (e) => (i(e), a),
99
+ stagger: (e, n = C.micro / 2) => {
100
100
  let r = t;
101
101
  return e.forEach((e, a) => {
102
102
  t = r + a * n, i({
103
103
  ...e,
104
104
  offset: 0
105
105
  });
106
- }), t = Math.max(t, r + (e.length - 1) * n + (e[0]?.duration ?? y.state)), o;
106
+ }), t = Math.max(t, r + (e.length - 1) * n + (e[0]?.duration ?? C.state)), a;
107
107
  },
108
108
  cues: () => [...e],
109
109
  duration: () => e.reduce((e, t) => Math.max(e, t.at + t.duration), 0),
110
110
  play: () => {
111
111
  r = !1;
112
- let t = o.duration();
113
- if (a(t) === 0 || typeof requestAnimationFrame != "function") {
112
+ let t = a.duration();
113
+ if (c(t) === 0 || typeof requestAnimationFrame != "function") {
114
114
  for (let t of e) t.run(1), t.onComplete?.();
115
115
  return Promise.resolve();
116
116
  }
@@ -121,7 +121,7 @@ var C = "http://www.w3.org/2000/svg", w = (e) => e.replace(/&/g, "&amp;").replac
121
121
  for (let t of e) {
122
122
  if (l < t.at) continue;
123
123
  let e = t.duration <= 0 ? 1 : (l - t.at) / t.duration, n = e >= 1 ? 1 : e;
124
- t.run(F(n)), n === 1 && !o.has(t.name) && (o.add(t.name), t.onComplete?.());
124
+ t.run(V(n)), n === 1 && !o.has(t.name) && (o.add(t.name), t.onComplete?.());
125
125
  }
126
126
  if (l >= t) return i();
127
127
  n = requestAnimationFrame(s);
@@ -133,9 +133,9 @@ var C = "http://www.w3.org/2000/svg", w = (e) => e.replace(/&/g, "&amp;").replac
133
133
  r = !0, n !== 0 && typeof cancelAnimationFrame == "function" && cancelAnimationFrame(n), n = 0;
134
134
  }
135
135
  };
136
- return o;
137
- }, L = (e) => {
138
- let t = I().add({
136
+ return a;
137
+ }, U = (e) => {
138
+ let t = H().add({
139
139
  name: "spotlight",
140
140
  duration: .72,
141
141
  run: e.spotlight
@@ -156,4 +156,4 @@ var C = "http://www.w3.org/2000/svg", w = (e) => e.replace(/&/g, "&amp;").replac
156
156
  }), n.length > 0 && t.stagger(n, .06), t;
157
157
  };
158
158
  //#endregion
159
- export { g as CANVAS, h as CONTEXT, p as DEFAULT_SIZE, u as DEFAULT_STROKE, y as DURATION, m as EASE, v as STATE_FILL, o as STATE_OPACITY, f as VARIANT_FILL, D as createIcon, I as createTimeline, _ as cssDuration, P as defineIconElement, O as iconDataUri, e as iconGroups, t as iconNames, n as isIconName, L as journeyChoreography, b as opticalStroke, N as optionsFromAttributes, r as paths, d as prefersReducedMotion, E as renderIcon, s as resolveContext, a as resolveDuration, j as resolveElementName, l as resolveFill, i as resolveGeometry, x as resolveStroke, S as resolveTransform, c as resolveVariantFill };
159
+ export { O as CANVAS, f as CONTEXT, l as DEFAULT_SIZE, D as DEFAULT_STROKE, C as DURATION, v as EASE, b as STATE_FILL, _ as STATE_OPACITY, m as VARIANT_FILL, y as align, S as canMorph, N as createIcon, H as createTimeline, x as cssDuration, B as defineIconElement, P as iconDataUri, e as iconGroups, t as iconNames, n as isIconName, U as journeyChoreography, u as lerp, p as opticalStroke, z as optionsFromAttributes, r as paths, g as planMorph, h as prefersReducedMotion, M as renderIcon, s as resolveContext, c as resolveDuration, L as resolveElementName, a as resolveFill, i as resolveGeometry, E as resolveStroke, o as resolveTransform, T as resolveVariantFill, w as sampleIcon, d as samplePath };
@@ -0,0 +1,166 @@
1
+ //#region src/core/props.ts
2
+ var e = 24, t = 24, n = 2, r = (e, t) => {
3
+ if (typeof e == "number") return Number.isFinite(e) ? e : t;
4
+ if (typeof e == "string") {
5
+ let n = Number.parseFloat(e);
6
+ return Number.isFinite(n) ? n : t;
7
+ }
8
+ return t;
9
+ }, i = (e, t, n) => {
10
+ let i = r(e, 2);
11
+ return !n || t <= 0 ? i : i * 24 / t;
12
+ }, a = (e) => (r(e, 0) % 360 + 360) % 360, o = (e) => e === "horizontal" ? [-1, 1] : e === "vertical" ? [1, -1] : e === "both" ? [-1, -1] : [1, 1], s = (e, t) => {
13
+ let n = a(e), [r, i] = o(t);
14
+ if (n === 0 && r === 1 && i === 1) return;
15
+ let s = ["translate(12 12)"];
16
+ return n !== 0 && s.push(`rotate(${n})`), (r !== 1 || i !== 1) && s.push(`scale(${r} ${i})`), s.push("translate(-12 -12)"), s.join(" ");
17
+ }, c = (e) => {
18
+ let t = r(e.size, 24);
19
+ return {
20
+ size: t,
21
+ strokeWidth: i(e.strokeWidth, t, e.absoluteStrokeWidth === !0),
22
+ transform: s(e.rotate, e.flip)
23
+ };
24
+ }, l = (e) => {
25
+ if (e === !0) return 1;
26
+ if (e === void 0 || e === !1) return 0;
27
+ let t = r(e, 0);
28
+ return t < 0 ? 0 : t > 1 ? 1 : t;
29
+ }, u = {
30
+ outline: 0,
31
+ duotone: .18,
32
+ filled: 1
33
+ }, d = (e) => u[e ?? "outline"] ?? 0, f = {
34
+ inline: {
35
+ size: 16,
36
+ strokeWidth: 2,
37
+ hitArea: 0
38
+ },
39
+ toolbar: {
40
+ size: 20,
41
+ strokeWidth: 2,
42
+ hitArea: 44
43
+ },
44
+ button: {
45
+ size: 18,
46
+ strokeWidth: 2,
47
+ hitArea: 44
48
+ },
49
+ navigation: {
50
+ size: 22,
51
+ strokeWidth: 1.9,
52
+ hitArea: 48
53
+ },
54
+ status: {
55
+ size: 20,
56
+ strokeWidth: 2,
57
+ hitArea: 0
58
+ },
59
+ hero: {
60
+ size: 40,
61
+ strokeWidth: 1.6,
62
+ hitArea: 0
63
+ }
64
+ }, p = (e) => e === void 0 ? null : f[e] ?? null, m = (e, t = 2) => e <= 16 ? t * .9 : e <= 20 ? t * .95 : e <= 28 ? t : e <= 40 ? t * .85 : t * .75, h = {
65
+ default: 0,
66
+ hover: .12,
67
+ active: 1,
68
+ selected: 1,
69
+ disabled: 0
70
+ }, g = {
71
+ default: 1,
72
+ hover: 1,
73
+ active: 1,
74
+ selected: 1,
75
+ disabled: .38
76
+ }, _ = "http://www.w3.org/2000/svg", v = () => {
77
+ if (typeof document > "u") return !1;
78
+ try {
79
+ let e = document.createElementNS(_, "path");
80
+ return typeof e.getTotalLength == "function" && typeof e.getPointAtLength == "function";
81
+ } catch {
82
+ return !1;
83
+ }
84
+ }, y = (e, t) => {
85
+ if (!v() || t < 2) return null;
86
+ try {
87
+ let n = document.createElementNS(_, "svg"), r = document.createElementNS(_, "path");
88
+ r.setAttribute("d", e), n.appendChild(r);
89
+ let i = r.getTotalLength();
90
+ if (!Number.isFinite(i) || i <= 0) return null;
91
+ let a = [];
92
+ for (let e = 0; e < t; e += 1) {
93
+ let n = r.getPointAtLength(i * e / (t - 1));
94
+ a.push({
95
+ x: n.x,
96
+ y: n.y
97
+ });
98
+ }
99
+ return a;
100
+ } catch {
101
+ return null;
102
+ }
103
+ }, b = (e, t) => {
104
+ if (e.length === 0) return null;
105
+ let n = [];
106
+ for (let r of e) {
107
+ let e = y(r, t);
108
+ if (e === null) return null;
109
+ n.push(e);
110
+ }
111
+ return n;
112
+ }, x = (e) => {
113
+ let t = 0, n = 0;
114
+ for (let r of e) t += r.x, n += r.y;
115
+ return {
116
+ x: t / e.length,
117
+ y: n / e.length
118
+ };
119
+ }, S = (e) => {
120
+ let t = x(e);
121
+ return e.map(() => t);
122
+ }, C = (e, t) => Math.hypot(e.x - t.x, e.y - t.y), w = (e, t) => {
123
+ if (e.length !== t.length || e.length === 0) return [...t];
124
+ let n = 0, r = Infinity, i = Math.max(1, Math.floor(t.length / 24));
125
+ for (let a = 0; a < t.length; a += i) {
126
+ let o = 0;
127
+ for (let n = 0; n < e.length; n += i) o += C(e[n], t[(n + a) % t.length]);
128
+ o < r && (r = o, n = a);
129
+ }
130
+ return t.map((e, r) => t[(r + n) % t.length]);
131
+ }, T = (e, t, n) => e + (t - e) * n, E = (e) => {
132
+ if (e.length === 0) return "";
133
+ let t = e[0], n = e.slice(1).map((e) => `L${e.x.toFixed(2)} ${e.y.toFixed(2)}`).join("");
134
+ return `M${t.x.toFixed(2)} ${t.y.toFixed(2)}${n}`;
135
+ }, D = (e, t, n = 64) => {
136
+ let r = b(e, n), i = b(t, n);
137
+ if (r === null || i === null) return null;
138
+ let a = Math.max(r.length, i.length), o = [], s = [];
139
+ for (let e = 0; e < a; e += 1) {
140
+ let t = r[e], n = i[e];
141
+ t !== void 0 && n !== void 0 ? (o.push([...t]), s.push(w(t, n))) : t === void 0 ? n !== void 0 && (o.push(S(n)), s.push([...n])) : (o.push([...t]), s.push(S(t)));
142
+ }
143
+ return {
144
+ from: o,
145
+ to: s,
146
+ at: (e) => {
147
+ let t = e <= 0 ? 0 : e >= 1 ? 1 : e;
148
+ return o.map((e, n) => {
149
+ let r = s[n];
150
+ return E(e.map((e, n) => ({
151
+ x: T(e.x, r[n].x, t),
152
+ y: T(e.y, r[n].y, t)
153
+ })));
154
+ });
155
+ }
156
+ };
157
+ }, O = {
158
+ micro: .18,
159
+ state: .28,
160
+ morph: .36
161
+ }, k = {
162
+ enter: "cubic-bezier(0.33, 1, 0.68, 1)",
163
+ morph: "cubic-bezier(0.65, 0, 0.35, 1)"
164
+ }, A = () => typeof window > "u" || typeof window.matchMedia != "function" ? !1 : window.matchMedia("(prefers-reduced-motion: reduce)").matches === !0, j = (e, t = A()) => t ? 0 : e, M = (e, t) => `${j(e, t)}s`;
165
+ //#endregion
166
+ export { c as C, l as S, s as T, p as _, j as a, t as b, T as c, y as d, f, m as g, u as h, A as i, D as l, g as m, k as n, w as o, h as p, M as r, v as s, O as t, b as u, d as v, i as w, n as x, e as y };
package/dist/vue.d.ts CHANGED
@@ -3,6 +3,7 @@ export { default as LvIcon } from './LvIcon.vue';
3
3
  export { default as LvIconButton } from './LvIconButton.vue';
4
4
  export { default as LvJourneyStep } from './LvJourneyStep.vue';
5
5
  export { default as LvIconInspector } from './LvIconInspector.vue';
6
+ export { default as LvMorphIcon } from './LvMorphIcon.vue';
6
7
  export { default as LvMenuToClose } from './animated/LvMenuToClose.vue';
7
8
  export { default as LvPlusToClose } from './animated/LvPlusToClose.vue';
8
9
  export { default as LvCheckmark } from './animated/LvCheckmark.vue';
package/dist/vue.js CHANGED
@@ -1,19 +1,19 @@
1
1
  import { paths as e } from "./paths.js";
2
- import { _ as t, c as n, f as r, g as i, i as a, n as o, o as s, r as c, s as l, t as u, u as d } from "./motion-72rOKpWt.js";
3
- import { Fragment as f, computed as p, createCommentVNode as m, createElementBlock as h, createElementVNode as g, createVNode as _, defineComponent as v, normalizeClass as y, normalizeStyle as b, openBlock as x, renderList as S, toDisplayString as C, unref as w } from "vue";
2
+ import { C as t, S as n, a as r, f as i, g as a, i as o, l as s, m as c, n as l, p as u, r as d, s as f, t as p, v as m } from "./motion-CBQXeIyE.js";
3
+ import { Fragment as h, computed as g, createCommentVNode as _, createElementBlock as v, createElementVNode as y, createVNode as b, defineComponent as x, normalizeClass as S, normalizeStyle as C, onBeforeUnmount as w, openBlock as T, ref as E, renderList as D, toDisplayString as O, unref as k, watch as A } from "vue";
4
4
  //#region src/LvIcon.vue?vue&type=script&setup=true&lang.ts
5
- var T = [
5
+ var j = [
6
6
  "width",
7
7
  "height",
8
8
  "stroke-width",
9
9
  "aria-hidden",
10
10
  "role",
11
11
  "aria-label"
12
- ], E = ["transform"], D = [
12
+ ], M = ["transform"], N = [
13
13
  "d",
14
14
  "fill",
15
15
  "fill-opacity"
16
- ], O = /* @__PURE__ */ v({
16
+ ], P = /* @__PURE__ */ x({
17
17
  __name: "LvIcon",
18
18
  props: {
19
19
  name: {},
@@ -31,15 +31,15 @@ var T = [
31
31
  flip: {},
32
32
  label: {}
33
33
  },
34
- setup(n) {
35
- let r = n, a = p(() => e[r.name] ?? []), o = p(() => t({
36
- size: r.size,
37
- strokeWidth: r.strokeWidth,
38
- absoluteStrokeWidth: r.absoluteStrokeWidth,
39
- rotate: r.rotate,
40
- flip: r.flip
41
- })), s = p(() => i(r.fill)), c = p(() => r.label == null || r.label.length === 0);
42
- return (e, t) => (x(), h("svg", {
34
+ setup(r) {
35
+ let i = r, a = g(() => e[i.name] ?? []), o = g(() => t({
36
+ size: i.size,
37
+ strokeWidth: i.strokeWidth,
38
+ absoluteStrokeWidth: i.absoluteStrokeWidth,
39
+ rotate: i.rotate,
40
+ flip: i.flip
41
+ })), s = g(() => n(i.fill)), c = g(() => i.label == null || i.label.length === 0);
42
+ return (e, t) => (T(), v("svg", {
43
43
  class: "lv-icon",
44
44
  xmlns: "http://www.w3.org/2000/svg",
45
45
  width: o.value.size,
@@ -52,15 +52,15 @@ var T = [
52
52
  "stroke-linejoin": "round",
53
53
  "aria-hidden": c.value ? "true" : void 0,
54
54
  role: c.value ? void 0 : "img",
55
- "aria-label": c.value ? void 0 : n.label
56
- }, [g("g", { transform: o.value.transform }, [(x(!0), h(f, null, S(a.value, (e, t) => (x(), h("path", {
55
+ "aria-label": c.value ? void 0 : r.label
56
+ }, [y("g", { transform: o.value.transform }, [(T(!0), v(h, null, D(a.value, (e, t) => (T(), v("path", {
57
57
  key: t,
58
58
  d: e,
59
59
  fill: s.value > 0 ? "currentColor" : "none",
60
60
  "fill-opacity": s.value > 0 ? s.value : void 0
61
- }, null, 8, D))), 128))], 8, E)], 8, T));
61
+ }, null, 8, N))), 128))], 8, M)], 8, j));
62
62
  }
63
- }), k = ["disabled", "aria-label"], A = /* @__PURE__ */ v({
63
+ }), F = ["disabled", "aria-label"], I = /* @__PURE__ */ x({
64
64
  __name: "LvIconButton",
65
65
  props: {
66
66
  icon: {},
@@ -79,33 +79,33 @@ var T = [
79
79
  }
80
80
  },
81
81
  setup(e) {
82
- let t = e, n = p(() => s[t.context] ?? s.button), i = p(() => t.size ?? n.value.size), a = p(() => Math.max(t.hitArea ?? n.value.hitArea, 44)), o = p(() => t.optical ? d(i.value, n.value.strokeWidth) : n.value.strokeWidth);
83
- return (t, n) => (x(), h("button", {
82
+ let t = e, n = g(() => i[t.context] ?? i.button), r = g(() => t.size ?? n.value.size), o = g(() => Math.max(t.hitArea ?? n.value.hitArea, 44)), s = g(() => t.optical ? a(r.value, n.value.strokeWidth) : n.value.strokeWidth);
83
+ return (t, n) => (T(), v("button", {
84
84
  type: "button",
85
- class: y(["lv-icon-button", { "is-disabled": e.disabled }]),
86
- style: b({ "--lv-target": `${a.value}px` }),
85
+ class: S(["lv-icon-button", { "is-disabled": e.disabled }]),
86
+ style: C({ "--lv-target": `${o.value}px` }),
87
87
  disabled: e.disabled,
88
88
  "aria-label": e.label
89
- }, [_(O, {
89
+ }, [b(P, {
90
90
  name: e.icon,
91
- size: i.value,
92
- "stroke-width": o.value,
93
- fill: w(r)(e.variant)
91
+ size: r.value,
92
+ "stroke-width": s.value,
93
+ fill: k(m)(e.variant)
94
94
  }, null, 8, [
95
95
  "name",
96
96
  "size",
97
97
  "stroke-width",
98
98
  "fill"
99
- ])], 14, k));
99
+ ])], 14, F));
100
100
  }
101
- }), j = [
101
+ }), L = [
102
102
  "width",
103
103
  "height",
104
104
  "stroke-width",
105
105
  "aria-hidden",
106
106
  "role",
107
107
  "aria-label"
108
- ], M = /* @__PURE__ */ v({
108
+ ], R = /* @__PURE__ */ x({
109
109
  __name: "LvJourneyStep",
110
110
  props: {
111
111
  state: { default: "pending" },
@@ -114,13 +114,13 @@ var T = [
114
114
  label: {}
115
115
  },
116
116
  setup(e) {
117
- let t = e, n = p(() => ({
118
- "--lv-duration": c(u.state),
119
- "--lv-ease": o.enter
120
- })), r = p(() => t.label == null || t.label.length === 0);
121
- return (t, i) => (x(), h("svg", {
122
- class: y(["lv-icon lv-icon--step", `is-${e.state}`]),
123
- style: b(n.value),
117
+ let t = e, n = g(() => ({
118
+ "--lv-duration": d(p.state),
119
+ "--lv-ease": l.enter
120
+ })), r = g(() => t.label == null || t.label.length === 0);
121
+ return (t, i) => (T(), v("svg", {
122
+ class: S(["lv-icon lv-icon--step", `is-${e.state}`]),
123
+ style: C(n.value),
124
124
  xmlns: "http://www.w3.org/2000/svg",
125
125
  width: e.size,
126
126
  height: e.size,
@@ -134,13 +134,13 @@ var T = [
134
134
  role: r.value ? void 0 : "img",
135
135
  "aria-label": r.value ? void 0 : e.label
136
136
  }, [...i[0] ||= [
137
- g("circle", {
137
+ y("circle", {
138
138
  class: "lv-icon__ring",
139
139
  cx: "12",
140
140
  cy: "12",
141
141
  r: "8.5"
142
142
  }, null, -1),
143
- g("circle", {
143
+ y("circle", {
144
144
  class: "lv-icon__dot",
145
145
  cx: "12",
146
146
  cy: "12",
@@ -148,17 +148,17 @@ var T = [
148
148
  fill: "currentColor",
149
149
  stroke: "none"
150
150
  }, null, -1),
151
- g("path", {
151
+ y("path", {
152
152
  class: "lv-icon__tick",
153
153
  d: "m8 12.25 2.5 2.5 5.5-5.75"
154
154
  }, null, -1),
155
- g("path", {
155
+ y("path", {
156
156
  class: "lv-icon__dash",
157
157
  d: "M8.5 12h7"
158
158
  }, null, -1)
159
- ]], 14, j));
159
+ ]], 14, L));
160
160
  }
161
- }), N = { class: "lv-inspector" }, P = { class: "lv-inspector__states" }, F = { class: "lv-inspector__caption" }, I = { class: "lv-inspector__facts" }, L = /* @__PURE__ */ v({
161
+ }), z = { class: "lv-inspector" }, B = { class: "lv-inspector__states" }, V = { class: "lv-inspector__caption" }, H = { class: "lv-inspector__facts" }, U = /* @__PURE__ */ x({
162
162
  __name: "LvIconInspector",
163
163
  props: {
164
164
  name: {},
@@ -166,15 +166,15 @@ var T = [
166
166
  strokeWidth: { default: 2 }
167
167
  },
168
168
  setup(t) {
169
- let r = t, i = [
169
+ let n = t, r = [
170
170
  "default",
171
171
  "hover",
172
172
  "active",
173
173
  "disabled"
174
- ], o = p(() => [
174
+ ], i = g(() => [
175
175
  {
176
176
  label: "Name",
177
- value: r.name
177
+ value: n.name
178
178
  },
179
179
  {
180
180
  label: "Grid",
@@ -182,51 +182,123 @@ var T = [
182
182
  },
183
183
  {
184
184
  label: "Paths",
185
- value: String(e[r.name]?.length ?? 0)
185
+ value: String(e[n.name]?.length ?? 0)
186
186
  },
187
187
  {
188
188
  label: "Stroke",
189
- value: `${r.strokeWidth}px`
189
+ value: `${n.strokeWidth}px`
190
190
  },
191
191
  {
192
192
  label: "Optical stroke",
193
- value: `${d(r.size, r.strokeWidth).toFixed(2)}px`
193
+ value: `${a(n.size, n.strokeWidth).toFixed(2)}px`
194
194
  },
195
195
  {
196
196
  label: "Motion",
197
- value: `${u.state * 1e3}ms state · ${u.morph * 1e3}ms morph`
197
+ value: `${p.state * 1e3}ms state · ${p.morph * 1e3}ms morph`
198
198
  },
199
199
  {
200
200
  label: "Reduced motion",
201
- value: a() ? "active — motion off" : "supported"
201
+ value: o() ? "active — motion off" : "supported"
202
202
  }
203
203
  ]);
204
- return (e, r) => (x(), h("div", N, [g("div", P, [(x(), h(f, null, S(i, (e) => g("div", {
204
+ return (e, n) => (T(), v("div", z, [y("div", B, [(T(), v(h, null, D(r, (e) => y("div", {
205
205
  key: e,
206
206
  class: "lv-inspector__state"
207
- }, [g("div", {
207
+ }, [y("div", {
208
208
  class: "lv-inspector__swatch",
209
- style: b({ opacity: w(n)[e] })
210
- }, [_(O, {
209
+ style: C({ opacity: k(c)[e] })
210
+ }, [b(P, {
211
211
  name: t.name,
212
212
  size: t.size,
213
213
  "stroke-width": t.strokeWidth,
214
- fill: w(l)[e]
214
+ fill: k(u)[e]
215
215
  }, null, 8, [
216
216
  "name",
217
217
  "size",
218
218
  "stroke-width",
219
219
  "fill"
220
- ])], 4), g("span", F, C(e), 1)])), 64))]), g("dl", I, [(x(!0), h(f, null, S(o.value, (e) => (x(), h(f, { key: e.label }, [g("dt", null, C(e.label), 1), g("dd", null, C(e.value), 1)], 64))), 128))])]));
220
+ ])], 4), y("span", V, O(e), 1)])), 64))]), y("dl", H, [(T(!0), v(h, null, D(i.value, (e) => (T(), v(h, { key: e.label }, [y("dt", null, O(e.label), 1), y("dd", null, O(e.value), 1)], 64))), 128))])]));
221
221
  }
222
- }), R = [
222
+ }), W = [
223
223
  "width",
224
224
  "height",
225
225
  "stroke-width",
226
226
  "aria-hidden",
227
227
  "role",
228
228
  "aria-label"
229
- ], z = /* @__PURE__ */ v({
229
+ ], G = ["transform"], K = ["d"], q = /* @__PURE__ */ x({
230
+ __name: "LvMorphIcon",
231
+ props: {
232
+ name: {},
233
+ size: { default: 24 },
234
+ strokeWidth: { default: 2 },
235
+ absoluteStrokeWidth: {
236
+ type: Boolean,
237
+ default: !1
238
+ },
239
+ flip: {},
240
+ rotate: {},
241
+ label: {},
242
+ duration: { default: p.morph },
243
+ resolution: { default: 64 }
244
+ },
245
+ emits: ["morphed"],
246
+ setup(n, { emit: i }) {
247
+ let a = n, o = i, c = E(e[a.name] ?? []), l = g(() => t({
248
+ size: a.size,
249
+ strokeWidth: a.strokeWidth,
250
+ absoluteStrokeWidth: a.absoluteStrokeWidth,
251
+ rotate: a.rotate,
252
+ flip: a.flip
253
+ })), u = 0, d = null, p = () => {
254
+ u !== 0 && typeof cancelAnimationFrame == "function" && cancelAnimationFrame(u), u = 0;
255
+ }, m = (t) => {
256
+ c.value = e[t] ?? [], o("morphed", t);
257
+ };
258
+ A(() => a.name, (t, n) => {
259
+ p();
260
+ let i = e[t];
261
+ if (i === void 0) return;
262
+ let o = r(a.duration);
263
+ if (!f() || o <= 0 || n === void 0 || (d = s(e[n] ?? [], i, a.resolution), d === null)) return m(t);
264
+ let l = performance.now(), h = (e) => {
265
+ let n = Math.min(1, (e - l) / (o * 1e3));
266
+ if (c.value = d.at(n < .5 ? 4 * n * n * n : 1 - (-2 * n + 2) ** 3 / 2), n < 1) {
267
+ u = requestAnimationFrame(h);
268
+ return;
269
+ }
270
+ m(t);
271
+ };
272
+ u = requestAnimationFrame(h);
273
+ }), w(p);
274
+ let _ = g(() => a.label == null || a.label.length === 0);
275
+ return (e, t) => (T(), v("svg", {
276
+ class: "lv-icon lv-icon--morph",
277
+ xmlns: "http://www.w3.org/2000/svg",
278
+ width: l.value.size,
279
+ height: l.value.size,
280
+ viewBox: "0 0 24 24",
281
+ fill: "none",
282
+ stroke: "currentColor",
283
+ "stroke-width": l.value.strokeWidth,
284
+ "stroke-linecap": "round",
285
+ "stroke-linejoin": "round",
286
+ "aria-hidden": _.value ? "true" : void 0,
287
+ role: _.value ? void 0 : "img",
288
+ "aria-label": _.value ? void 0 : n.label
289
+ }, [y("g", { transform: l.value.transform }, [(T(!0), v(h, null, D(c.value, (e, t) => (T(), v("path", {
290
+ key: t,
291
+ d: e
292
+ }, null, 8, K))), 128))], 8, G)], 8, W));
293
+ }
294
+ }), J = [
295
+ "width",
296
+ "height",
297
+ "stroke-width",
298
+ "aria-hidden",
299
+ "role",
300
+ "aria-label"
301
+ ], Y = /* @__PURE__ */ x({
230
302
  __name: "LvMenuToClose",
231
303
  props: {
232
304
  open: {
@@ -240,20 +312,20 @@ var T = [
240
312
  default: !1
241
313
  },
242
314
  label: {},
243
- duration: { default: u.morph }
315
+ duration: { default: p.morph }
244
316
  },
245
317
  setup(e) {
246
- let n = e, r = p(() => t({
318
+ let n = e, r = g(() => t({
247
319
  size: n.size,
248
320
  strokeWidth: n.strokeWidth,
249
321
  absoluteStrokeWidth: n.absoluteStrokeWidth
250
- })), i = p(() => ({
251
- "--lv-duration": c(n.duration),
252
- "--lv-ease": o.morph
253
- })), a = p(() => n.label == null || n.label.length === 0);
254
- return (t, n) => (x(), h("svg", {
255
- class: y(["lv-icon lv-icon--menu", { "is-open": e.open }]),
256
- style: b(i.value),
322
+ })), i = g(() => ({
323
+ "--lv-duration": d(n.duration),
324
+ "--lv-ease": l.morph
325
+ })), a = g(() => n.label == null || n.label.length === 0);
326
+ return (t, n) => (T(), v("svg", {
327
+ class: S(["lv-icon lv-icon--menu", { "is-open": e.open }]),
328
+ style: C(i.value),
257
329
  xmlns: "http://www.w3.org/2000/svg",
258
330
  width: r.value.size,
259
331
  height: r.value.size,
@@ -266,37 +338,37 @@ var T = [
266
338
  role: a.value ? void 0 : "img",
267
339
  "aria-label": a.value ? void 0 : e.label
268
340
  }, [...n[0] ||= [
269
- g("line", {
341
+ y("line", {
270
342
  class: "lv-icon__bar lv-icon__bar--top",
271
343
  x1: "4",
272
344
  y1: "7",
273
345
  x2: "20",
274
346
  y2: "7"
275
347
  }, null, -1),
276
- g("line", {
348
+ y("line", {
277
349
  class: "lv-icon__bar lv-icon__bar--mid",
278
350
  x1: "4",
279
351
  y1: "12",
280
352
  x2: "20",
281
353
  y2: "12"
282
354
  }, null, -1),
283
- g("line", {
355
+ y("line", {
284
356
  class: "lv-icon__bar lv-icon__bar--bottom",
285
357
  x1: "4",
286
358
  y1: "17",
287
359
  x2: "20",
288
360
  y2: "17"
289
361
  }, null, -1)
290
- ]], 14, R));
362
+ ]], 14, J));
291
363
  }
292
- }), B = [
364
+ }), X = [
293
365
  "width",
294
366
  "height",
295
367
  "stroke-width",
296
368
  "aria-hidden",
297
369
  "role",
298
370
  "aria-label"
299
- ], V = /* @__PURE__ */ v({
371
+ ], Z = /* @__PURE__ */ x({
300
372
  __name: "LvPlusToClose",
301
373
  props: {
302
374
  open: {
@@ -310,20 +382,20 @@ var T = [
310
382
  default: !1
311
383
  },
312
384
  label: {},
313
- duration: { default: u.morph }
385
+ duration: { default: p.morph }
314
386
  },
315
387
  setup(e) {
316
- let n = e, r = p(() => t({
388
+ let n = e, r = g(() => t({
317
389
  size: n.size,
318
390
  strokeWidth: n.strokeWidth,
319
391
  absoluteStrokeWidth: n.absoluteStrokeWidth
320
- })), i = p(() => ({
321
- "--lv-duration": c(n.duration),
322
- "--lv-ease": o.morph
323
- })), a = p(() => n.label == null || n.label.length === 0);
324
- return (t, n) => (x(), h("svg", {
325
- class: y(["lv-icon lv-icon--plus", { "is-open": e.open }]),
326
- style: b(i.value),
392
+ })), i = g(() => ({
393
+ "--lv-duration": d(n.duration),
394
+ "--lv-ease": l.morph
395
+ })), a = g(() => n.label == null || n.label.length === 0);
396
+ return (t, n) => (T(), v("svg", {
397
+ class: S(["lv-icon lv-icon--plus", { "is-open": e.open }]),
398
+ style: C(i.value),
327
399
  xmlns: "http://www.w3.org/2000/svg",
328
400
  width: r.value.size,
329
401
  height: r.value.size,
@@ -335,32 +407,32 @@ var T = [
335
407
  "aria-hidden": a.value ? "true" : void 0,
336
408
  role: a.value ? void 0 : "img",
337
409
  "aria-label": a.value ? void 0 : e.label
338
- }, [...n[0] ||= [g("g", { class: "lv-icon__cross" }, [g("line", {
410
+ }, [...n[0] ||= [y("g", { class: "lv-icon__cross" }, [y("line", {
339
411
  x1: "12",
340
412
  y1: "5",
341
413
  x2: "12",
342
414
  y2: "19"
343
- }), g("line", {
415
+ }), y("line", {
344
416
  x1: "5",
345
417
  y1: "12",
346
418
  x2: "19",
347
419
  y2: "12"
348
- })], -1)]], 14, B));
420
+ })], -1)]], 14, X));
349
421
  }
350
- }), H = [
422
+ }), Q = [
351
423
  "width",
352
424
  "height",
353
425
  "stroke-width",
354
426
  "aria-hidden",
355
427
  "role",
356
428
  "aria-label"
357
- ], U = {
429
+ ], $ = {
358
430
  key: 0,
359
431
  class: "lv-icon__ring",
360
432
  cx: "12",
361
433
  cy: "12",
362
434
  r: "9"
363
- }, W = ["d"], G = /* @__PURE__ */ v({
435
+ }, ee = ["d"], te = /* @__PURE__ */ x({
364
436
  __name: "LvCheckmark",
365
437
  props: {
366
438
  checked: {
@@ -378,20 +450,20 @@ var T = [
378
450
  default: !1
379
451
  },
380
452
  label: {},
381
- duration: { default: u.state }
453
+ duration: { default: p.state }
382
454
  },
383
455
  setup(e) {
384
- let n = e, r = p(() => t({
456
+ let n = e, r = g(() => t({
385
457
  size: n.size,
386
458
  strokeWidth: n.strokeWidth,
387
459
  absoluteStrokeWidth: n.absoluteStrokeWidth
388
- })), i = p(() => ({
389
- "--lv-duration": c(n.duration),
390
- "--lv-ease": o.enter
391
- })), a = p(() => n.label == null || n.label.length === 0);
392
- return (t, n) => (x(), h("svg", {
393
- class: y(["lv-icon lv-icon--check", { "is-checked": e.checked }]),
394
- style: b(i.value),
460
+ })), i = g(() => ({
461
+ "--lv-duration": d(n.duration),
462
+ "--lv-ease": l.enter
463
+ })), a = g(() => n.label == null || n.label.length === 0);
464
+ return (t, n) => (T(), v("svg", {
465
+ class: S(["lv-icon lv-icon--check", { "is-checked": e.checked }]),
466
+ style: C(i.value),
395
467
  xmlns: "http://www.w3.org/2000/svg",
396
468
  width: r.value.size,
397
469
  height: r.value.size,
@@ -404,17 +476,17 @@ var T = [
404
476
  "aria-hidden": a.value ? "true" : void 0,
405
477
  role: a.value ? void 0 : "img",
406
478
  "aria-label": a.value ? void 0 : e.label
407
- }, [e.circle ? (x(), h("circle", U)) : m("", !0), g("path", {
479
+ }, [e.circle ? (T(), v("circle", $)) : _("", !0), y("path", {
408
480
  class: "lv-icon__tick",
409
481
  d: e.circle ? "m8.25 12.25 2.5 2.5 5-5.5" : "m5 12.5 4.5 4.5L19 7.5"
410
- }, null, 8, W)], 14, H));
482
+ }, null, 8, ee)], 14, Q));
411
483
  }
412
- }), K = [
484
+ }), ne = [
413
485
  "width",
414
486
  "height",
415
487
  "stroke-width",
416
488
  "aria-label"
417
- ], q = /* @__PURE__ */ v({
489
+ ], re = /* @__PURE__ */ x({
418
490
  __name: "LvLoading",
419
491
  props: {
420
492
  size: { default: 24 },
@@ -427,14 +499,14 @@ var T = [
427
499
  label: { default: "Loading" }
428
500
  },
429
501
  setup(e) {
430
- let n = e, r = p(() => t({
502
+ let n = e, r = g(() => t({
431
503
  size: n.size,
432
504
  strokeWidth: n.strokeWidth,
433
505
  absoluteStrokeWidth: n.absoluteStrokeWidth
434
- })), i = p(() => ({ "--lv-duration": c(n.duration) }));
435
- return (t, n) => (x(), h("svg", {
506
+ })), i = g(() => ({ "--lv-duration": d(n.duration) }));
507
+ return (t, n) => (T(), v("svg", {
436
508
  class: "lv-icon lv-icon--loading",
437
- style: b(i.value),
509
+ style: C(i.value),
438
510
  xmlns: "http://www.w3.org/2000/svg",
439
511
  width: r.value.size,
440
512
  height: r.value.size,
@@ -445,25 +517,25 @@ var T = [
445
517
  "stroke-linecap": "round",
446
518
  role: "status",
447
519
  "aria-label": e.label
448
- }, [...n[0] ||= [g("circle", {
520
+ }, [...n[0] ||= [y("circle", {
449
521
  class: "lv-icon__track",
450
522
  cx: "12",
451
523
  cy: "12",
452
524
  r: "9",
453
525
  opacity: "0.22"
454
- }, null, -1), g("path", {
526
+ }, null, -1), y("path", {
455
527
  class: "lv-icon__arc",
456
528
  d: "M21 12a9 9 0 0 0-9-9"
457
- }, null, -1)]], 12, K));
529
+ }, null, -1)]], 12, ne));
458
530
  }
459
- }), J = [
531
+ }), ie = [
460
532
  "width",
461
533
  "height",
462
534
  "stroke-width",
463
535
  "aria-hidden",
464
536
  "role",
465
537
  "aria-label"
466
- ], Y = /* @__PURE__ */ v({
538
+ ], ae = /* @__PURE__ */ x({
467
539
  __name: "LvArrowMotion",
468
540
  props: {
469
541
  direction: { default: "right" },
@@ -475,10 +547,10 @@ var T = [
475
547
  default: !1
476
548
  },
477
549
  label: {},
478
- duration: { default: u.micro }
550
+ duration: { default: p.micro }
479
551
  },
480
552
  setup(e) {
481
- let n = e, r = p(() => t({
553
+ let n = e, r = g(() => t({
482
554
  size: n.size,
483
555
  strokeWidth: n.strokeWidth,
484
556
  absoluteStrokeWidth: n.absoluteStrokeWidth
@@ -487,15 +559,15 @@ var T = [
487
559
  down: 90,
488
560
  left: 180,
489
561
  up: 270
490
- }, a = p(() => ({
491
- "--lv-duration": c(n.duration),
492
- "--lv-ease": o.enter,
562
+ }, a = g(() => ({
563
+ "--lv-duration": d(n.duration),
564
+ "--lv-ease": l.enter,
493
565
  "--lv-travel": `${n.travel}px`,
494
566
  "--lv-rotate": `${i[n.direction]}deg`
495
- })), s = p(() => n.label == null || n.label.length === 0);
496
- return (t, n) => (x(), h("svg", {
567
+ })), o = g(() => n.label == null || n.label.length === 0);
568
+ return (t, n) => (T(), v("svg", {
497
569
  class: "lv-icon lv-icon--arrow",
498
- style: b(a.value),
570
+ style: C(a.value),
499
571
  xmlns: "http://www.w3.org/2000/svg",
500
572
  width: r.value.size,
501
573
  height: r.value.size,
@@ -505,17 +577,17 @@ var T = [
505
577
  "stroke-width": r.value.strokeWidth,
506
578
  "stroke-linecap": "round",
507
579
  "stroke-linejoin": "round",
508
- "aria-hidden": s.value ? "true" : void 0,
509
- role: s.value ? void 0 : "img",
510
- "aria-label": s.value ? void 0 : e.label
511
- }, [...n[0] ||= [g("g", { class: "lv-icon__arrow-inner" }, [g("path", {
580
+ "aria-hidden": o.value ? "true" : void 0,
581
+ role: o.value ? void 0 : "img",
582
+ "aria-label": o.value ? void 0 : e.label
583
+ }, [...n[0] ||= [y("g", { class: "lv-icon__arrow-inner" }, [y("path", {
512
584
  class: "lv-icon__shaft",
513
585
  d: "M4 12h15"
514
- }), g("path", {
586
+ }), y("path", {
515
587
  class: "lv-icon__head",
516
588
  d: "m13 6 6 6-6 6"
517
- })], -1)]], 12, J));
589
+ })], -1)]], 12, ie));
518
590
  }
519
591
  });
520
592
  //#endregion
521
- export { Y as LvArrowMotion, G as LvCheckmark, O as LvIcon, A as LvIconButton, L as LvIconInspector, M as LvJourneyStep, q as LvLoading, z as LvMenuToClose, V as LvPlusToClose };
593
+ export { ae as LvArrowMotion, te as LvCheckmark, P as LvIcon, I as LvIconButton, U as LvIconInspector, R as LvJourneyStep, re as LvLoading, Y as LvMenuToClose, q as LvMorphIcon, Z as LvPlusToClose };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovince/icons",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "A motion-aware icon system for Vue 3 \u2014 24x24 geometry, variable weight and fill, animated state transitions.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,85 +0,0 @@
1
- //#region src/core/props.ts
2
- var e = 24, t = 24, n = 2, r = (e, t) => {
3
- if (typeof e == "number") return Number.isFinite(e) ? e : t;
4
- if (typeof e == "string") {
5
- let n = Number.parseFloat(e);
6
- return Number.isFinite(n) ? n : t;
7
- }
8
- return t;
9
- }, i = (e, t, n) => {
10
- let i = r(e, 2);
11
- return !n || t <= 0 ? i : i * 24 / t;
12
- }, a = (e) => (r(e, 0) % 360 + 360) % 360, o = (e) => e === "horizontal" ? [-1, 1] : e === "vertical" ? [1, -1] : e === "both" ? [-1, -1] : [1, 1], s = (e, t) => {
13
- let n = a(e), [r, i] = o(t);
14
- if (n === 0 && r === 1 && i === 1) return;
15
- let s = ["translate(12 12)"];
16
- return n !== 0 && s.push(`rotate(${n})`), (r !== 1 || i !== 1) && s.push(`scale(${r} ${i})`), s.push("translate(-12 -12)"), s.join(" ");
17
- }, c = (e) => {
18
- let t = r(e.size, 24);
19
- return {
20
- size: t,
21
- strokeWidth: i(e.strokeWidth, t, e.absoluteStrokeWidth === !0),
22
- transform: s(e.rotate, e.flip)
23
- };
24
- }, l = (e) => {
25
- if (e === !0) return 1;
26
- if (e === void 0 || e === !1) return 0;
27
- let t = r(e, 0);
28
- return t < 0 ? 0 : t > 1 ? 1 : t;
29
- }, u = {
30
- outline: 0,
31
- duotone: .18,
32
- filled: 1
33
- }, d = (e) => u[e ?? "outline"] ?? 0, f = {
34
- inline: {
35
- size: 16,
36
- strokeWidth: 2,
37
- hitArea: 0
38
- },
39
- toolbar: {
40
- size: 20,
41
- strokeWidth: 2,
42
- hitArea: 44
43
- },
44
- button: {
45
- size: 18,
46
- strokeWidth: 2,
47
- hitArea: 44
48
- },
49
- navigation: {
50
- size: 22,
51
- strokeWidth: 1.9,
52
- hitArea: 48
53
- },
54
- status: {
55
- size: 20,
56
- strokeWidth: 2,
57
- hitArea: 0
58
- },
59
- hero: {
60
- size: 40,
61
- strokeWidth: 1.6,
62
- hitArea: 0
63
- }
64
- }, p = (e) => e === void 0 ? null : f[e] ?? null, m = (e, t = 2) => e <= 16 ? t * .9 : e <= 20 ? t * .95 : e <= 28 ? t : e <= 40 ? t * .85 : t * .75, h = {
65
- default: 0,
66
- hover: .12,
67
- active: 1,
68
- selected: 1,
69
- disabled: 0
70
- }, g = {
71
- default: 1,
72
- hover: 1,
73
- active: 1,
74
- selected: 1,
75
- disabled: .38
76
- }, _ = {
77
- micro: .18,
78
- state: .28,
79
- morph: .36
80
- }, v = {
81
- enter: "cubic-bezier(0.33, 1, 0.68, 1)",
82
- morph: "cubic-bezier(0.65, 0, 0.35, 1)"
83
- }, y = () => typeof window > "u" || typeof window.matchMedia != "function" ? !1 : window.matchMedia("(prefers-reduced-motion: reduce)").matches === !0, b = (e, t = y()) => t ? 0 : e, x = (e, t) => `${b(e, t)}s`;
84
- //#endregion
85
- export { c as _, b as a, g as c, p as d, d as f, l as g, n as h, y as i, u as l, t as m, v as n, f as o, e as p, x as r, h as s, _ as t, m as u, i as v, s as y };