@getvitops/utils 0.8.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +105 -0
- package/dist/color/index.d.mts +60 -3
- package/dist/color/index.d.mts.map +1 -1
- package/dist/color/index.mjs +113 -123
- package/dist/color/index.mjs.map +1 -1
- package/dist/index.d.mts +9 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +9 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,110 @@
|
|
|
1
1
|
# @getvitops/utils
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- bb92a14: **The colour system is rebuilt on a target-prefixed grammar and a shared lightness ladder.**
|
|
8
|
+
This is a breaking change to every colour token and utility class.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
Two axes shared one class namespace — functional _planes_ (`--<role>-bg-muted`) and
|
|
13
|
+
appearance-relative _stops_ (`--color-<role>-muted`) — arbitrated by a "plane wins" rule. The
|
|
14
|
+
result was not a scale. On the shipped palette, light mode:
|
|
15
|
+
|
|
16
|
+
| class | resolved to | step |
|
|
17
|
+
| ---------------------------------- | ------------ | --------------------------------------------- |
|
|
18
|
+
| `bg-ui-accent-x-muted` | stop | 100 |
|
|
19
|
+
| `bg-ui-accent-muted` | plane | 100 — identical, so `x-muted` was a dead rung |
|
|
20
|
+
| `bg-ui-accent` | plane | 50 — _lighter_ than both its "muted" rungs |
|
|
21
|
+
| `border-ui-accent-muted` / `-bold` | stop / plane | 300 / 300 — identical |
|
|
22
|
+
| `text-ui-accent-bold` | stop | 700 — _lighter_ than `text-…-muted` (800) |
|
|
23
|
+
|
|
24
|
+
Every family was non-monotonic, two had duplicate rungs, and `--color-<role>-muted` was
|
|
25
|
+
unreachable through any `bg-` class.
|
|
26
|
+
|
|
27
|
+
## The new grammar
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
--color-<target>-<role>[-<variant>] target ∈ bg | text | icon | border
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The target is **inside** the name, so `bg-danger-muted` and `text-danger-muted` are different
|
|
34
|
+
tokens and there is nothing left to arbitrate. **The class name is the token name minus
|
|
35
|
+
`--color-`** — one vocabulary instead of two.
|
|
36
|
+
|
|
37
|
+
Variants are ordinal (`xx-muted` < `x-muted` < `muted` < bare < `bold` < `x-bold`) and the
|
|
38
|
+
tables are sparse: only cells that hold their contrast target exist.
|
|
39
|
+
|
|
40
|
+
## Role kinds
|
|
41
|
+
|
|
42
|
+
`colors.roles` values may now be `{ hue, kind }` as well as a bare hue string:
|
|
43
|
+
|
|
44
|
+
```jsonc
|
|
45
|
+
"roles": {
|
|
46
|
+
"danger": "rust", // shorthand => chromatic
|
|
47
|
+
"surface": { "hue": "navy", "kind": "surface" }
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- **`surface`** — a page/panel colour: `bg-<role>` is the card, `bg-<role>-muted` the page
|
|
52
|
+
behind it, `bg-<role>-x-muted` a well, `bg-<role>-bold` the inverse surface. Full text scale.
|
|
53
|
+
- **`chromatic`** (default) — a signal colour: tints (`bg-<role>-x-muted`/`-muted`) and solids
|
|
54
|
+
(`bg-<role>-solid[-bold|-x-bold]`), with **no bare `bg-<role>`** — say how loud you mean.
|
|
55
|
+
`text-on-<role>` is the guaranteed foreground for the solid family.
|
|
56
|
+
|
|
57
|
+
## Palette generation
|
|
58
|
+
|
|
59
|
+
Every ramp now sits on one **fixed lightness ladder** (50 → L 0.98 … 950 → L 0.21); only chroma
|
|
60
|
+
and hue vary. That is what makes a step mean the same lightness in every hue. Previously each
|
|
61
|
+
seed transposed the curve, so relative luminance at step 300 ranged from 0.253 to 0.384 across
|
|
62
|
+
the shipped palette — the same variant read differently depending on the role.
|
|
63
|
+
|
|
64
|
+
Authored colours are still reproduced **exactly**. A `seed`, an `anchors` entry or a `tones`
|
|
65
|
+
value is pinned verbatim at its nearest step; every other step takes the ladder. Snapping brand
|
|
66
|
+
colours to the ladder was measured and rejected: 11 of 18 real brand hexes moved beyond a
|
|
67
|
+
just-noticeable difference (worst ΔE-OK 0.050 — Facebook's `#1877F2` → `#0067e1`) and six left
|
|
68
|
+
sRGB gamut. Deviation is now bounded and local to pinned steps, and warns past ~0.03 L.
|
|
69
|
+
|
|
70
|
+
Two tones that claim the same step now **error** instead of one silently overwriting the other;
|
|
71
|
+
the record form (`tones: { "600": "…", "700": "…" }`) is how you resolve it.
|
|
72
|
+
|
|
73
|
+
## New
|
|
74
|
+
- **`icon-<role>`** — a non-text tier, so a glyph may run more vivid than text. `icon` is now a
|
|
75
|
+
default utility family alongside `bg`/`text`/`border`.
|
|
76
|
+
- **`--color-border-focus`** — the focus-ring tone, taken from `ui-primary`'s solid.
|
|
77
|
+
- **Contrast is enforced at build time**, not only in tests: text ≥ APCA Lc 75 on its primary
|
|
78
|
+
background, ≥ 60 on secondary planes, icons and surface boundaries ≥ 45, both appearances.
|
|
79
|
+
A violation now fails `generate`. Chromatic text is checked against the _surface_ planes it
|
|
80
|
+
actually sits on, not only its own tints. `text-<role>-x-muted` (placeholder) and `-xx-muted`
|
|
81
|
+
(disabled) are explicitly exempt; nothing else is.
|
|
82
|
+
|
|
83
|
+
## Migrating
|
|
84
|
+
|
|
85
|
+
Rename `--<role>-<suffix>` → `--color-<target>-<role>[-<variant>]`, and the same for classes:
|
|
86
|
+
|
|
87
|
+
| before | after |
|
|
88
|
+
| --------------------------------------- | ---------------------------------------------------------------- |
|
|
89
|
+
| `--<role>-bg` / `bg-<role>` (chromatic) | `--color-bg-<role>-x-muted` / `bg-<role>-x-muted` |
|
|
90
|
+
| `--<role>-bg-muted` | `--color-bg-<role>-muted` |
|
|
91
|
+
| `--<role>-solid` / `-solid-bold` | `--color-bg-<role>-solid` / `-solid-bold` |
|
|
92
|
+
| `--<role>-on-solid` / `text-on-<role>` | `--color-text-on-<role>` (class unchanged) |
|
|
93
|
+
| `--<role>-text` / `-text-muted` | `--color-text-<role>` / `-muted` |
|
|
94
|
+
| `--<role>-border` / `-border-bold` | `--color-border-<role>` / `-bold` |
|
|
95
|
+
| `--color-<role>-muted` (stop) | judge by use: `--color-bg-<role>-muted` or `--color-text-<role>` |
|
|
96
|
+
|
|
97
|
+
**`surface` background names rotate**, value-preserving: what was `--surface-bg` (the page) is
|
|
98
|
+
now `--color-bg-surface-muted`; what was `--surface-bg-bold` (raised) is now
|
|
99
|
+
`--color-bg-surface`. Elevation is expressed by which token you reach for — page `bg-muted`,
|
|
100
|
+
card `bg` — rather than a raised/sunken pair, which is what lets a future surfaces axis flatten
|
|
101
|
+
it without touching markup.
|
|
102
|
+
|
|
103
|
+
`vitops lint` reports role classes that no longer resolve, and now derives its suggestions from
|
|
104
|
+
what the generator actually emits rather than a hand-maintained list.
|
|
105
|
+
|
|
106
|
+
## 0.9.0
|
|
107
|
+
|
|
3
108
|
## 0.8.0
|
|
4
109
|
|
|
5
110
|
## 0.7.0
|
package/dist/color/index.d.mts
CHANGED
|
@@ -68,6 +68,30 @@ interface HarmonyDefinition {
|
|
|
68
68
|
primaryIndex: number;
|
|
69
69
|
}
|
|
70
70
|
declare const HARMONY_DEFINITIONS: Record<HarmonyType, HarmonyDefinition>;
|
|
71
|
+
/**
|
|
72
|
+
* The shared lightness ladder every ramp is built on (lightest → darkest).
|
|
73
|
+
*
|
|
74
|
+
* Fixed, NOT seed-derived. Two hues at the same step have to read equally light,
|
|
75
|
+
* otherwise one contrast table cannot serve every hue and a `muted` variant means
|
|
76
|
+
* something different depending on which role you ask. Only chroma and hue vary
|
|
77
|
+
* between ramps.
|
|
78
|
+
*
|
|
79
|
+
* The previous engine transposed this curve onto each seed, which let relative
|
|
80
|
+
* luminance at step 300 range from 0.253 (rust) to 0.384 (amber) across the
|
|
81
|
+
* shipped palette — the drift this replaces.
|
|
82
|
+
*
|
|
83
|
+
* Anchored steps are the one deliberate exception: see `generateOklchPalette`.
|
|
84
|
+
*/
|
|
85
|
+
declare const LIGHTNESS_LADDER: Record<StepName, number>;
|
|
86
|
+
/**
|
|
87
|
+
* Chroma a ramp decays to beyond its outermost anchors, so the near-white and
|
|
88
|
+
* near-black ends keep a whisper of the hue instead of going flat grey. The dark
|
|
89
|
+
* end carries slightly more because chroma reads weaker against black.
|
|
90
|
+
*/
|
|
91
|
+
declare const ENDPOINT_CHROMA: {
|
|
92
|
+
readonly light: 0.008;
|
|
93
|
+
readonly dark: 0.015;
|
|
94
|
+
};
|
|
71
95
|
interface OklchColor {
|
|
72
96
|
l: number;
|
|
73
97
|
c: number;
|
|
@@ -80,8 +104,36 @@ interface OklchColor {
|
|
|
80
104
|
*/
|
|
81
105
|
declare function parseOklch(oklchString: string): OklchColor;
|
|
82
106
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
107
|
+
* The ladder step whose lightness is closest to `lightness` — i.e. where a
|
|
108
|
+
* supplied colour naturally belongs.
|
|
109
|
+
*/
|
|
110
|
+
declare function assignStepByLightness(lightness: number): StepName;
|
|
111
|
+
/**
|
|
112
|
+
* How far an anchored colour sits from its step's ladder lightness.
|
|
113
|
+
*
|
|
114
|
+
* The generator surfaces this as a warning: a large deviation is legal (the
|
|
115
|
+
* caller asked for that exact colour) but it means the hue will read heavier or
|
|
116
|
+
* lighter than its siblings at that step, which is worth knowing rather than
|
|
117
|
+
* discovering later.
|
|
118
|
+
*/
|
|
119
|
+
declare function ladderDeviation(step: StepName, lightness: number): number;
|
|
120
|
+
/**
|
|
121
|
+
* Build a complete 11-step OKLCH ramp from one or more anchor colours.
|
|
122
|
+
*
|
|
123
|
+
* **Ladder-first with exact anchors.** Every anchor is reproduced *verbatim* at
|
|
124
|
+
* its step; every other step takes its lightness from `LIGHTNESS_LADDER`, with
|
|
125
|
+
* chroma and hue interpolated between the flanking anchors and decayed toward
|
|
126
|
+
* `ENDPOINT_CHROMA` beyond the outermost ones.
|
|
127
|
+
*
|
|
128
|
+
* The consequence is the point: a client's brand hex survives byte-for-byte,
|
|
129
|
+
* while the other ten steps stay directly comparable to every other hue. The
|
|
130
|
+
* deviation from the ladder is bounded and *local to anchored steps* — unlike
|
|
131
|
+
* the previous engine, which warped the whole ramp to fit its anchors so every
|
|
132
|
+
* step drifted.
|
|
133
|
+
*
|
|
134
|
+
* Chroma may come out beyond the sRGB gamut here; that is deliberate.
|
|
135
|
+
* `oklchStringToHex` gamut-maps with the CSS algorithm, which reduces chroma
|
|
136
|
+
* while holding lightness, so the ladder survives the conversion.
|
|
85
137
|
*/
|
|
86
138
|
declare function generateOklchPalette(input: string | string[] | Record<string, string>): Record<StepName, string>;
|
|
87
139
|
/** APCA lightness-contrast (Lc) magnitude between a foreground and background. */
|
|
@@ -95,6 +147,11 @@ declare function pickOn(bg: string, hue?: number): string;
|
|
|
95
147
|
* The tinted off-white / off-black endpoints for a hue — white/black with a
|
|
96
148
|
* whisper of the hue mixed in. These are the text/background tints every ramp
|
|
97
149
|
* needs (and the one exception strict brand kits allow).
|
|
150
|
+
*
|
|
151
|
+
* Derived from `LIGHTNESS_LADDER` and `ENDPOINT_CHROMA` rather than its own
|
|
152
|
+
* literals, so a strict tone kit's endpoints land on the same ladder rungs a
|
|
153
|
+
* generated ramp would have used. This is the single definition — callers must
|
|
154
|
+
* not hand-write their own near-white/near-black.
|
|
98
155
|
*/
|
|
99
156
|
declare function tintedEndpoints(hue: number, chroma?: number): {
|
|
100
157
|
light: string;
|
|
@@ -140,5 +197,5 @@ declare const DEFAULT_FUNCTIONAL_HUES: {
|
|
|
140
197
|
*/
|
|
141
198
|
declare function suggestFunctionalColorHue(type: keyof typeof DEFAULT_FUNCTIONAL_HUES, existingHues: number[]): number;
|
|
142
199
|
//#endregion
|
|
143
|
-
export { COLOR_GROUPS, ColorGroup, DEFAULT_FUNCTIONAL_HUES, HARMONY_DEFINITIONS, HARMONY_STRATEGIES, HARMONY_TYPES, HarmonyDefinition, HarmonyOption, HarmonyStrategy, HarmonyType, RgbResult, STEP_NAMES, StepName, applyHarmonyStrategy, contrastLc, formatColorName, gamutMapOklchToHex, generateOklchPalette, getColorName, getColorNameWithHue, getHarmonySuggestions, hexToOklch, oklchStringToHex, oklchToHex, oklchToP3, oklchToSrgb, parseOklch, pickOn, suggestFunctionalColorHue, tintedEndpoints };
|
|
200
|
+
export { COLOR_GROUPS, ColorGroup, DEFAULT_FUNCTIONAL_HUES, ENDPOINT_CHROMA, HARMONY_DEFINITIONS, HARMONY_STRATEGIES, HARMONY_TYPES, HarmonyDefinition, HarmonyOption, HarmonyStrategy, HarmonyType, LIGHTNESS_LADDER, RgbResult, STEP_NAMES, StepName, applyHarmonyStrategy, assignStepByLightness, contrastLc, formatColorName, gamutMapOklchToHex, generateOklchPalette, getColorName, getColorNameWithHue, getHarmonySuggestions, hexToOklch, ladderDeviation, oklchStringToHex, oklchToHex, oklchToP3, oklchToSrgb, parseOklch, pickOn, suggestFunctionalColorHue, tintedEndpoints };
|
|
144
201
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/color/colors.ts","../../src/color/color-harmony.ts"],"mappings":";UAkBiB,SAAA;EACf,CAAA;EACA,CAAA;EACA,CAAA;EACA,OAAA;EAHA;EAKA,aAAA;AAAA;;;;AAAa;iBAOC,WAAA,CAAY,CAAA,UAAW,CAAA,UAAW,CAAA,WAAY,SAAS;;;;;iBAmBvD,SAAA,CAAU,CAAA,UAAW,CAAA,UAAW,CAAA,WAAY,SAAS;;;;AAnBE;iBAsCvD,kBAAA,CACd,CAAA,UACA,CAAA,UACA,CAAA,UACA,KAAA;AAAA,cAUW,UAAA;AAAA,KACD,QAAA,WAAmB,UAAU;AAAA,cAE5B,YAAA;AAAA,KAWD,UAAA,WAAqB,YAAY;;;;iBAK7B,UAAA,CAAW,GAAA;EAAgB,CAAA;EAAW,CAAA;EAAW,CAAA;AAAA;;;;iBAajD,UAAA,CAAW,KAAA;EAAS,CAAA;EAAW,CAAA;EAAW,CAAA;AAAA;;;;AAhC+B;iBA8CzE,gBAAA,CAAiB,WAAmB;;;;AA7CX;iBA8DzB,eAAA,CAAgB,IAAY;;;;iBA+G5B,YAAA,CAAa,GAAW;AAhKxC;;;AAAA,iBAsLgB,mBAAA,CAAoB,GAAW;AAAA,cAclC,aAAA;AAAA,KASD,WAAA,WAAsB,aAAa;AAAA,UAE9B,iBAAA;EACf,KAAA;EACA,OAAA;EACA,YAAA;AAAA;AAAA,cAGW,mBAAA,EAAqB,MAAA,CAAO,WAAA,EAAa,iBAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/color/colors.ts","../../src/color/color-harmony.ts"],"mappings":";UAkBiB,SAAA;EACf,CAAA;EACA,CAAA;EACA,CAAA;EACA,OAAA;EAHA;EAKA,aAAA;AAAA;;;;AAAa;iBAOC,WAAA,CAAY,CAAA,UAAW,CAAA,UAAW,CAAA,WAAY,SAAS;;;;;iBAmBvD,SAAA,CAAU,CAAA,UAAW,CAAA,UAAW,CAAA,WAAY,SAAS;;;;AAnBE;iBAsCvD,kBAAA,CACd,CAAA,UACA,CAAA,UACA,CAAA,UACA,KAAA;AAAA,cAUW,UAAA;AAAA,KACD,QAAA,WAAmB,UAAU;AAAA,cAE5B,YAAA;AAAA,KAWD,UAAA,WAAqB,YAAY;;;;iBAK7B,UAAA,CAAW,GAAA;EAAgB,CAAA;EAAW,CAAA;EAAW,CAAA;AAAA;;;;iBAajD,UAAA,CAAW,KAAA;EAAS,CAAA;EAAW,CAAA;EAAW,CAAA;AAAA;;;;AAhC+B;iBA8CzE,gBAAA,CAAiB,WAAmB;;;;AA7CX;iBA8DzB,eAAA,CAAgB,IAAY;;;;iBA+G5B,YAAA,CAAa,GAAW;AAhKxC;;;AAAA,iBAsLgB,mBAAA,CAAoB,GAAW;AAAA,cAclC,aAAA;AAAA,KASD,WAAA,WAAsB,aAAa;AAAA,UAE9B,iBAAA;EACf,KAAA;EACA,OAAA;EACA,YAAA;AAAA;AAAA,cAGW,mBAAA,EAAqB,MAAA,CAAO,WAAA,EAAa,iBAAA;;;AAhNY;AAalE;;;;;;;;;AAAqE;AAcrE;cAyOa,gBAAA,EAAkB,MAAM,CAAC,QAAA;;;AAzOc;AAiBpD;;cA2Oa,eAAA;EAAA,SAAwD,KAAA;EAAA,SAAA,IAAA;AAAA;AAAA,UAE3D,UAAA;EACR,CAAA;EACA,CAAA;EACA,CAAA;AAAA;;;;AA3G6C;AAc/C;iBAqGgB,UAAA,CAAW,WAAA,WAAsB,UAAU;;;AA7FjD;AACV;iBA4HgB,qBAAA,CAAsB,SAAA,WAAoB,QAAQ;;;AA5HnB;AAE/C;;;;;iBAiJgB,eAAA,CAAgB,IAAA,EAAM,QAAQ,EAAE,SAAA;;;AA9IlC;AAGd;;;;;;;;;;;;AAAuE;AAoDvE;;iBAgHgB,oBAAA,CACd,KAAA,sBAA2B,MAAA,mBAC1B,MAAA,CAAO,QAAA;;iBAsFM,UAAA,CAAW,EAAA,UAAY,EAAU;AArLjD;;;;AAAA,iBA6LgB,MAAA,CAAO,EAAA,UAAY,GAAY;AA7LuB;;;;;;;;AAKnE;AAQH;AAbsE,iBA8MtD,eAAA,CAAgB,GAAA,UAAa,MAAA;EAAoB,KAAA;EAAe,IAAA;AAAA;;;;AAzjBhF;;KCdY,eAAA;AAAA,UAWK,aAAA;EACf,EAAA,EAAI,eAAe;EACnB,KAAA;EACA,WAAA;EACA,QAAA;AAAA;AAAA,cAGW,kBAAA,EAAoB,aAAa;ADE/B;AAOf;;AAPe,iBC0DC,oBAAA,CAAqB,OAAA,UAAiB,QAAA,EAAU,eAAe;;;;iBAgB/D,qBAAA,CACd,OAAA,WACC,KAAK;EAAG,QAAA,EAAU,eAAA;EAAiB,GAAA;EAAa,KAAA;EAAe,WAAA;AAAA;;;;cAYrD,uBAAA;EAAA;;;;;;;;iBAUG,yBAAA,CACd,IAAA,eAAmB,uBAAuB,EAC1C,YAAA"}
|
package/dist/color/index.mjs
CHANGED
|
@@ -332,18 +332,41 @@ const HARMONY_DEFINITIONS = {
|
|
|
332
332
|
primaryIndex: 1
|
|
333
333
|
}
|
|
334
334
|
};
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
335
|
+
/**
|
|
336
|
+
* The shared lightness ladder every ramp is built on (lightest → darkest).
|
|
337
|
+
*
|
|
338
|
+
* Fixed, NOT seed-derived. Two hues at the same step have to read equally light,
|
|
339
|
+
* otherwise one contrast table cannot serve every hue and a `muted` variant means
|
|
340
|
+
* something different depending on which role you ask. Only chroma and hue vary
|
|
341
|
+
* between ramps.
|
|
342
|
+
*
|
|
343
|
+
* The previous engine transposed this curve onto each seed, which let relative
|
|
344
|
+
* luminance at step 300 range from 0.253 (rust) to 0.384 (amber) across the
|
|
345
|
+
* shipped palette — the drift this replaces.
|
|
346
|
+
*
|
|
347
|
+
* Anchored steps are the one deliberate exception: see `generateOklchPalette`.
|
|
348
|
+
*/
|
|
349
|
+
const LIGHTNESS_LADDER = {
|
|
350
|
+
50: .98,
|
|
351
|
+
100: .95,
|
|
352
|
+
200: .9,
|
|
353
|
+
300: .83,
|
|
354
|
+
400: .74,
|
|
355
|
+
500: .65,
|
|
356
|
+
600: .54,
|
|
357
|
+
700: .47,
|
|
358
|
+
800: .38,
|
|
359
|
+
900: .29,
|
|
360
|
+
950: .21
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* Chroma a ramp decays to beyond its outermost anchors, so the near-white and
|
|
364
|
+
* near-black ends keep a whisper of the hue instead of going flat grey. The dark
|
|
365
|
+
* end carries slightly more because chroma reads weaker against black.
|
|
366
|
+
*/
|
|
367
|
+
const ENDPOINT_CHROMA = {
|
|
368
|
+
light: .008,
|
|
369
|
+
dark: .015
|
|
347
370
|
};
|
|
348
371
|
/**
|
|
349
372
|
* Parses an OKLCH CSS string into numerical components.
|
|
@@ -367,69 +390,21 @@ function lerp(start, end, factor) {
|
|
|
367
390
|
return start + factor * (end - start);
|
|
368
391
|
}
|
|
369
392
|
/**
|
|
370
|
-
*
|
|
393
|
+
* Interpolate hue the short way round the wheel. A ramp anchored at 350° and 10°
|
|
394
|
+
* spans 20°, not 340° — the naive lerp sent it the long way through cyan.
|
|
371
395
|
*/
|
|
372
|
-
function
|
|
373
|
-
|
|
374
|
-
if (sortedAnchorSteps.length === 1) {
|
|
375
|
-
const anchorStep = sortedAnchorSteps[0];
|
|
376
|
-
const anchorL = parsedAnchors[anchorStep].l;
|
|
377
|
-
const defaultAnchorL = DEFAULT_LIGHTNESS_SCALE[anchorStep];
|
|
378
|
-
for (const step of STEP_NAMES) {
|
|
379
|
-
if (step === anchorStep) {
|
|
380
|
-
transposedScale[step] = anchorL;
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
const defaultStepL = DEFAULT_LIGHTNESS_SCALE[step];
|
|
384
|
-
if (defaultStepL > defaultAnchorL) transposedScale[step] = lerp(anchorL, .97, (defaultStepL - defaultAnchorL) / (1 - defaultAnchorL));
|
|
385
|
-
else transposedScale[step] = lerp(.05, anchorL, defaultStepL / defaultAnchorL);
|
|
386
|
-
}
|
|
387
|
-
return transposedScale;
|
|
388
|
-
}
|
|
389
|
-
for (const step of STEP_NAMES) {
|
|
390
|
-
const anchored = parsedAnchors[step];
|
|
391
|
-
if (anchored) {
|
|
392
|
-
transposedScale[step] = anchored.l;
|
|
393
|
-
continue;
|
|
394
|
-
}
|
|
395
|
-
let lowerStep = null;
|
|
396
|
-
let upperStep = null;
|
|
397
|
-
for (let i = sortedAnchorSteps.length - 1; i >= 0; i--) {
|
|
398
|
-
const candidate = sortedAnchorSteps[i];
|
|
399
|
-
if (candidate < step) {
|
|
400
|
-
lowerStep = candidate;
|
|
401
|
-
break;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
for (const anchorStep of sortedAnchorSteps) if (anchorStep > step) {
|
|
405
|
-
upperStep = anchorStep;
|
|
406
|
-
break;
|
|
407
|
-
}
|
|
408
|
-
if (lowerStep !== null && upperStep !== null) {
|
|
409
|
-
const lowerL = parsedAnchors[lowerStep].l;
|
|
410
|
-
const upperL = parsedAnchors[upperStep].l;
|
|
411
|
-
const span = upperStep - lowerStep;
|
|
412
|
-
transposedScale[step] = lerp(lowerL, upperL, (step - lowerStep) / span);
|
|
413
|
-
} else if (lowerStep !== null) {
|
|
414
|
-
const lowerL = parsedAnchors[lowerStep].l;
|
|
415
|
-
const defaultLowerL = DEFAULT_LIGHTNESS_SCALE[lowerStep];
|
|
416
|
-
transposedScale[step] = lerp(.05, lowerL, DEFAULT_LIGHTNESS_SCALE[step] / defaultLowerL);
|
|
417
|
-
} else if (upperStep !== null) {
|
|
418
|
-
const upperL = parsedAnchors[upperStep].l;
|
|
419
|
-
const defaultUpperL = DEFAULT_LIGHTNESS_SCALE[upperStep];
|
|
420
|
-
transposedScale[step] = lerp(upperL, .97, (DEFAULT_LIGHTNESS_SCALE[step] - defaultUpperL) / (1 - defaultUpperL));
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
return transposedScale;
|
|
396
|
+
function lerpHue(start, end, factor) {
|
|
397
|
+
return (start + (((end - start) % 360 + 540) % 360 - 180) * factor + 360) % 360;
|
|
424
398
|
}
|
|
425
399
|
/**
|
|
426
|
-
*
|
|
400
|
+
* The ladder step whose lightness is closest to `lightness` — i.e. where a
|
|
401
|
+
* supplied colour naturally belongs.
|
|
427
402
|
*/
|
|
428
403
|
function assignStepByLightness(lightness) {
|
|
429
404
|
let closestStep = 500;
|
|
430
|
-
let minDiff = Math.abs(lightness -
|
|
405
|
+
let minDiff = Math.abs(lightness - LIGHTNESS_LADDER[500]);
|
|
431
406
|
for (const step of STEP_NAMES) {
|
|
432
|
-
const diff = Math.abs(lightness -
|
|
407
|
+
const diff = Math.abs(lightness - LIGHTNESS_LADDER[step]);
|
|
433
408
|
if (diff < minDiff) {
|
|
434
409
|
minDiff = diff;
|
|
435
410
|
closestStep = step;
|
|
@@ -438,68 +413,78 @@ function assignStepByLightness(lightness) {
|
|
|
438
413
|
return closestStep;
|
|
439
414
|
}
|
|
440
415
|
/**
|
|
441
|
-
*
|
|
442
|
-
*
|
|
416
|
+
* How far an anchored colour sits from its step's ladder lightness.
|
|
417
|
+
*
|
|
418
|
+
* The generator surfaces this as a warning: a large deviation is legal (the
|
|
419
|
+
* caller asked for that exact colour) but it means the hue will read heavier or
|
|
420
|
+
* lighter than its siblings at that step, which is worth knowing rather than
|
|
421
|
+
* discovering later.
|
|
422
|
+
*/
|
|
423
|
+
function ladderDeviation(step, lightness) {
|
|
424
|
+
return lightness - LIGHTNESS_LADDER[step];
|
|
425
|
+
}
|
|
426
|
+
/** Absolute chroma ceiling — beyond this nothing survives gamut mapping anyway. */
|
|
427
|
+
const MAX_CHROMA = .37;
|
|
428
|
+
/**
|
|
429
|
+
* Build a complete 11-step OKLCH ramp from one or more anchor colours.
|
|
430
|
+
*
|
|
431
|
+
* **Ladder-first with exact anchors.** Every anchor is reproduced *verbatim* at
|
|
432
|
+
* its step; every other step takes its lightness from `LIGHTNESS_LADDER`, with
|
|
433
|
+
* chroma and hue interpolated between the flanking anchors and decayed toward
|
|
434
|
+
* `ENDPOINT_CHROMA` beyond the outermost ones.
|
|
435
|
+
*
|
|
436
|
+
* The consequence is the point: a client's brand hex survives byte-for-byte,
|
|
437
|
+
* while the other ten steps stay directly comparable to every other hue. The
|
|
438
|
+
* deviation from the ladder is bounded and *local to anchored steps* — unlike
|
|
439
|
+
* the previous engine, which warped the whole ramp to fit its anchors so every
|
|
440
|
+
* step drifted.
|
|
441
|
+
*
|
|
442
|
+
* Chroma may come out beyond the sRGB gamut here; that is deliberate.
|
|
443
|
+
* `oklchStringToHex` gamut-maps with the CSS algorithm, which reduces chroma
|
|
444
|
+
* while holding lightness, so the ladder survives the conversion.
|
|
443
445
|
*/
|
|
444
446
|
function generateOklchPalette(input) {
|
|
445
447
|
let anchors = {};
|
|
446
|
-
if (typeof input === "string")
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
} else if (Array.isArray(input)) for (const colorStr of input) {
|
|
450
|
-
const step = assignStepByLightness(parseOklch(colorStr).l);
|
|
451
|
-
anchors[step] = colorStr;
|
|
452
|
-
}
|
|
453
|
-
else if (typeof input === "object") anchors = input;
|
|
448
|
+
if (typeof input === "string") anchors[assignStepByLightness(parseOklch(input).l)] = input;
|
|
449
|
+
else if (Array.isArray(input)) for (const colorStr of input) anchors[assignStepByLightness(parseOklch(colorStr).l)] = colorStr;
|
|
450
|
+
else if (typeof input === "object" && input !== null) anchors = { ...input };
|
|
454
451
|
else throw new Error("Input must be a color string, array of colors, or object with step assignments");
|
|
455
452
|
const parsedAnchors = {};
|
|
456
|
-
for (const key
|
|
457
|
-
const
|
|
458
|
-
const
|
|
453
|
+
for (const [key, value] of Object.entries(anchors)) parsedAnchors[Number(key)] = parseOklch(value);
|
|
454
|
+
const anchorSteps = Object.keys(parsedAnchors).map(Number).sort((a, b) => a - b);
|
|
455
|
+
const idx = (step) => STEP_NAMES.indexOf(step);
|
|
456
|
+
const lastIdx = STEP_NAMES.length - 1;
|
|
459
457
|
const palette = {};
|
|
460
458
|
for (const step of STEP_NAMES) {
|
|
461
459
|
if (parsedAnchors[step]) {
|
|
462
460
|
palette[step] = anchors[step];
|
|
463
461
|
continue;
|
|
464
462
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
h_int = lerp(startColor.h, endColor.h, factor);
|
|
486
|
-
} else if (startStep !== null) {
|
|
487
|
-
const a = parsedAnchors[startStep];
|
|
488
|
-
c_int = a.c;
|
|
489
|
-
h_int = a.h;
|
|
490
|
-
} else if (endStep !== null) {
|
|
491
|
-
const a = parsedAnchors[endStep];
|
|
492
|
-
c_int = a.c;
|
|
493
|
-
h_int = a.h;
|
|
463
|
+
const lighter = [...anchorSteps].reverse().find((s) => s < step);
|
|
464
|
+
const darker = anchorSteps.find((s) => s > step);
|
|
465
|
+
let chroma;
|
|
466
|
+
let hue;
|
|
467
|
+
if (lighter !== void 0 && darker !== void 0) {
|
|
468
|
+
const a = parsedAnchors[lighter];
|
|
469
|
+
const b = parsedAnchors[darker];
|
|
470
|
+
const factor = (idx(step) - idx(lighter)) / (idx(darker) - idx(lighter));
|
|
471
|
+
chroma = lerp(a.c, b.c, factor);
|
|
472
|
+
hue = lerpHue(a.h, b.h, factor);
|
|
473
|
+
} else if (lighter !== void 0) {
|
|
474
|
+
const a = parsedAnchors[lighter];
|
|
475
|
+
const factor = (idx(step) - idx(lighter)) / (lastIdx - idx(lighter));
|
|
476
|
+
chroma = lerp(a.c, ENDPOINT_CHROMA.dark, factor);
|
|
477
|
+
hue = a.h;
|
|
478
|
+
} else if (darker !== void 0) {
|
|
479
|
+
const b = parsedAnchors[darker];
|
|
480
|
+
const factor = (idx(darker) - idx(step)) / idx(darker);
|
|
481
|
+
chroma = lerp(b.c, ENDPOINT_CHROMA.light, factor);
|
|
482
|
+
hue = b.h;
|
|
494
483
|
} else {
|
|
495
|
-
|
|
496
|
-
|
|
484
|
+
chroma = .1;
|
|
485
|
+
hue = 0;
|
|
497
486
|
}
|
|
498
|
-
|
|
499
|
-
const dampeningFactor = l_int < .25 ? .3 + l_int / .25 * .7 : l_int > .75 ? .3 + (1 - l_int) / .25 * .7 : 1;
|
|
500
|
-
c_int *= dampeningFactor;
|
|
501
|
-
c_int = Math.min(c_int, .37);
|
|
502
|
-
palette[step] = `oklch(${(l_int * 100).toFixed(2) + "%"} ${c_int.toFixed(4)} ${h_int.toFixed(2)})`;
|
|
487
|
+
palette[step] = `oklch(${(LIGHTNESS_LADDER[step] * 100).toFixed(2) + "%"} ${Math.min(chroma, MAX_CHROMA).toFixed(4)} ${hue.toFixed(2)})`;
|
|
503
488
|
}
|
|
504
489
|
return palette;
|
|
505
490
|
}
|
|
@@ -529,17 +514,22 @@ function pickOn(bg, hue) {
|
|
|
529
514
|
* The tinted off-white / off-black endpoints for a hue — white/black with a
|
|
530
515
|
* whisper of the hue mixed in. These are the text/background tints every ramp
|
|
531
516
|
* needs (and the one exception strict brand kits allow).
|
|
517
|
+
*
|
|
518
|
+
* Derived from `LIGHTNESS_LADDER` and `ENDPOINT_CHROMA` rather than its own
|
|
519
|
+
* literals, so a strict tone kit's endpoints land on the same ladder rungs a
|
|
520
|
+
* generated ramp would have used. This is the single definition — callers must
|
|
521
|
+
* not hand-write their own near-white/near-black.
|
|
532
522
|
*/
|
|
533
|
-
function tintedEndpoints(hue, chroma
|
|
523
|
+
function tintedEndpoints(hue, chroma) {
|
|
534
524
|
return {
|
|
535
525
|
light: oklchToHex({
|
|
536
|
-
l:
|
|
537
|
-
c: Math.min(chroma, .02),
|
|
526
|
+
l: LIGHTNESS_LADDER[50],
|
|
527
|
+
c: Math.min(chroma ?? ENDPOINT_CHROMA.light, .02),
|
|
538
528
|
h: hue
|
|
539
529
|
}),
|
|
540
530
|
dark: oklchToHex({
|
|
541
|
-
l:
|
|
542
|
-
c: Math.min(chroma * 1.5, .03),
|
|
531
|
+
l: LIGHTNESS_LADDER[950],
|
|
532
|
+
c: Math.min((chroma ?? ENDPOINT_CHROMA.dark) * 1.5, .03),
|
|
543
533
|
h: hue
|
|
544
534
|
})
|
|
545
535
|
};
|
|
@@ -647,5 +637,5 @@ function suggestFunctionalColorHue(type, existingHues) {
|
|
|
647
637
|
}
|
|
648
638
|
|
|
649
639
|
//#endregion
|
|
650
|
-
export { COLOR_GROUPS, DEFAULT_FUNCTIONAL_HUES, HARMONY_DEFINITIONS, HARMONY_STRATEGIES, HARMONY_TYPES, STEP_NAMES, applyHarmonyStrategy, contrastLc, formatColorName, gamutMapOklchToHex, generateOklchPalette, getColorName, getColorNameWithHue, getHarmonySuggestions, hexToOklch, oklchStringToHex, oklchToHex, oklchToP3, oklchToSrgb, parseOklch, pickOn, suggestFunctionalColorHue, tintedEndpoints };
|
|
640
|
+
export { COLOR_GROUPS, DEFAULT_FUNCTIONAL_HUES, ENDPOINT_CHROMA, HARMONY_DEFINITIONS, HARMONY_STRATEGIES, HARMONY_TYPES, LIGHTNESS_LADDER, STEP_NAMES, applyHarmonyStrategy, assignStepByLightness, contrastLc, formatColorName, gamutMapOklchToHex, generateOklchPalette, getColorName, getColorNameWithHue, getHarmonySuggestions, hexToOklch, ladderDeviation, oklchStringToHex, oklchToHex, oklchToP3, oklchToSrgb, parseOklch, pickOn, suggestFunctionalColorHue, tintedEndpoints };
|
|
651
641
|
//# sourceMappingURL=index.mjs.map
|
package/dist/color/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["OKLCH_Space","sRGB_Space","P3_Space"],"sources":["../../src/color/colors.ts","../../src/color/color-harmony.ts"],"sourcesContent":["import Color from 'colorjs.io';\nimport {\n OKLCH as OKLCH_Space,\n sRGB as sRGB_Space,\n P3 as P3_Space,\n ColorSpace,\n to,\n toGamutCSS,\n clone,\n serialize,\n type PlainColorObject,\n} from 'colorjs.io/fn';\n\n// Register color spaces once for functional API\nColorSpace.register(OKLCH_Space);\nColorSpace.register(sRGB_Space);\nColorSpace.register(P3_Space);\n\nexport interface RgbResult {\n r: number;\n g: number;\n b: number;\n inGamut: boolean;\n /** Max channel overshoot beyond [0,1] before clamping. 0 when in gamut. */\n gamutDistance: number;\n}\n\n/**\n * Convert OKLCh to sRGB, returning 0-255 clamped values with gamut flag.\n * Fast path for per-pixel canvas rendering (no gamut mapping, just clamp).\n */\nexport function oklchToSrgb(l: number, c: number, h: number): RgbResult {\n const col: PlainColorObject = { space: OKLCH_Space, coords: [l, c, h], alpha: 1 };\n const rgb = to(col, sRGB_Space);\n const [r, g, b] = rgb.coords;\n const inGamut = r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1;\n const gamutDistance = inGamut ? 0 : Math.max(-r, r - 1, -g, g - 1, -b, b - 1, 0);\n return {\n r: Math.max(0, Math.min(255, Math.round(r * 255))),\n g: Math.max(0, Math.min(255, Math.round(g * 255))),\n b: Math.max(0, Math.min(255, Math.round(b * 255))),\n inGamut,\n gamutDistance,\n };\n}\n\n/**\n * Convert OKLCh to Display P3, returning 0-255 clamped values with gamut flag.\n * Fast path for per-pixel canvas rendering on P3 displays.\n */\nexport function oklchToP3(l: number, c: number, h: number): RgbResult {\n const col: PlainColorObject = { space: OKLCH_Space, coords: [l, c, h], alpha: 1 };\n const rgb = to(col, P3_Space);\n const [r, g, b] = rgb.coords;\n const inGamut = r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1;\n const gamutDistance = inGamut ? 0 : Math.max(-r, r - 1, -g, g - 1, -b, b - 1, 0);\n return {\n r: Math.max(0, Math.min(255, Math.round(r * 255))),\n g: Math.max(0, Math.min(255, Math.round(g * 255))),\n b: Math.max(0, Math.min(255, Math.round(b * 255))),\n inGamut,\n gamutDistance,\n };\n}\n\n/**\n * Gamut-map an OKLCh color using the CSS gamut mapping algorithm, return hex.\n * Slower than oklchToSrgb/oklchToP3 (uses iterative reduction), use for single colors only.\n */\nexport function gamutMapOklchToHex(\n l: number,\n c: number,\n h: number,\n space: 'srgb' | 'p3' = 'srgb',\n): string {\n const col: PlainColorObject = { space: OKLCH_Space, coords: [l, c, h], alpha: 1 };\n const targetSpace = space === 'p3' ? P3_Space : sRGB_Space;\n const mapped = toGamutCSS(clone(col), { space: targetSpace });\n const rgb = to(mapped, sRGB_Space);\n return serialize(rgb, { format: 'hex' });\n}\n\n// Standard 11-step scale - will be transposed based on input anchors\nexport const STEP_NAMES = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const;\nexport type StepName = (typeof STEP_NAMES)[number];\n\nexport const COLOR_GROUPS = [\n 'neutral',\n 'brand',\n 'primary',\n 'accent',\n 'complement',\n 'success',\n 'warning',\n 'error',\n 'info',\n] as const;\nexport type ColorGroup = (typeof COLOR_GROUPS)[number];\n\n/**\n * Convert hex color to OKLCH components\n */\nexport function hexToOklch(hex: string): { l: number; c: number; h: number } {\n const color = new Color(hex);\n const oklch = color.to('oklch');\n return {\n l: oklch.coords[0],\n c: oklch.coords[1],\n h: oklch.coords[2] || 0,\n };\n}\n\n/**\n * Convert OKLCH components to hex color\n */\nexport function oklchToHex(oklch: { l: number; c: number; h: number }): string {\n const color = new Color('oklch', [oklch.l, oklch.c, oklch.h]);\n // Convert to sRGB and clamp to gamut, then format as hex\n const srgb = color.to('srgb');\n if (!srgb.inGamut()) {\n srgb.toGamut({ method: 'css' });\n }\n return srgb.toString({ format: 'hex' });\n}\n\n/**\n * Convert OKLCH CSS string to hex color\n * @example oklchStringToHex(\"oklch(50% 0.15 270)\") => \"#8b5cf6\"\n */\nexport function oklchStringToHex(oklchString: string): string {\n try {\n const color = new Color(oklchString);\n const srgb = color.to('srgb');\n if (!srgb.inGamut()) {\n srgb.toGamut({ method: 'css' });\n }\n return srgb.toString({ format: 'hex' });\n } catch {\n return '#808080';\n }\n}\n\n/**\n * Format a color name by separating compound words\n * Examples: \"mediumseagreen\" -> \"Medium Sea Green\", \"darkblue\" -> \"Dark Blue\"\n */\nexport function formatColorName(name: string): string {\n if (!name) return 'Unknown';\n\n // Handle special cases with proper word separation\n const specialCases: Record<string, string> = {\n aliceblue: 'Alice Blue',\n antiquewhite: 'Antique White',\n blanchedalmond: 'Blanched Almond',\n blueviolet: 'Blue Violet',\n burlywood: 'Burly Wood',\n cadetblue: 'Cadet Blue',\n cornflowerblue: 'Cornflower Blue',\n darkblue: 'Dark Blue',\n darkcyan: 'Dark Cyan',\n darkgoldenrod: 'Dark Goldenrod',\n darkgray: 'Dark Gray',\n darkgreen: 'Dark Green',\n darkgrey: 'Dark Grey',\n darkkhaki: 'Dark Khaki',\n darkmagenta: 'Dark Magenta',\n darkolivegreen: 'Dark Olive Green',\n darkorange: 'Dark Orange',\n darkorchid: 'Dark Orchid',\n darkred: 'Dark Red',\n darksalmon: 'Dark Salmon',\n darkseagreen: 'Dark Sea Green',\n darkslateblue: 'Dark Slate Blue',\n darkslategray: 'Dark Slate Gray',\n darkslategrey: 'Dark Slate Grey',\n darkturquoise: 'Dark Turquoise',\n darkviolet: 'Dark Violet',\n deeppink: 'Deep Pink',\n deepskyblue: 'Deep Sky Blue',\n dimgray: 'Dim Gray',\n dimgrey: 'Dim Grey',\n dodgerblue: 'Dodger Blue',\n floralwhite: 'Floral White',\n forestgreen: 'Forest Green',\n ghostwhite: 'Ghost White',\n greenyellow: 'Green Yellow',\n hotpink: 'Hot Pink',\n indianred: 'Indian Red',\n lavenderblush: 'Lavender Blush',\n lawngreen: 'Lawn Green',\n lemonchiffon: 'Lemon Chiffon',\n lightblue: 'Light Blue',\n lightcoral: 'Light Coral',\n lightcyan: 'Light Cyan',\n lightgoldenrodyellow: 'Light Goldenrod Yellow',\n lightgray: 'Light Gray',\n lightgreen: 'Light Green',\n lightgrey: 'Light Grey',\n lightpink: 'Light Pink',\n lightsalmon: 'Light Salmon',\n lightseagreen: 'Light Sea Green',\n lightskyblue: 'Light Sky Blue',\n lightslategray: 'Light Slate Gray',\n lightslategrey: 'Light Slate Grey',\n lightsteelblue: 'Light Steel Blue',\n lightyellow: 'Light Yellow',\n limegreen: 'Lime Green',\n mediumaquamarine: 'Medium Aquamarine',\n mediumblue: 'Medium Blue',\n mediumorchid: 'Medium Orchid',\n mediumpurple: 'Medium Purple',\n mediumseagreen: 'Medium Sea Green',\n mediumslateblue: 'Medium Slate Blue',\n mediumspringgreen: 'Medium Spring Green',\n mediumturquoise: 'Medium Turquoise',\n mediumvioletred: 'Medium Violet Red',\n midnightblue: 'Midnight Blue',\n mintcream: 'Mint Cream',\n mistyrose: 'Misty Rose',\n navajowhite: 'Navajo White',\n oldlace: 'Old Lace',\n olivedrab: 'Olive Drab',\n orangered: 'Orange Red',\n palegoldenrod: 'Pale Goldenrod',\n palegreen: 'Pale Green',\n paleturquoise: 'Pale Turquoise',\n palevioletred: 'Pale Violet Red',\n papayawhip: 'Papaya Whip',\n peachpuff: 'Peach Puff',\n powderblue: 'Powder Blue',\n rosybrown: 'Rosy Brown',\n royalblue: 'Royal Blue',\n saddlebrown: 'Saddle Brown',\n sandybrown: 'Sandy Brown',\n seagreen: 'Sea Green',\n skyblue: 'Sky Blue',\n slateblue: 'Slate Blue',\n slategray: 'Slate Gray',\n slategrey: 'Slate Grey',\n springgreen: 'Spring Green',\n steelblue: 'Steel Blue',\n whitesmoke: 'White Smoke',\n yellowgreen: 'Yellow Green',\n };\n\n const lowerName = name.toLowerCase();\n if (specialCases[lowerName]) {\n return specialCases[lowerName];\n }\n\n // Default: just capitalize first letter\n return name.charAt(0).toUpperCase() + name.slice(1);\n}\n\n/**\n * Get the closest CSS color name for a hex color\n */\nexport function getColorName(hex: string): string {\n try {\n const color = new Color(hex);\n const oklch = color.to('oklch');\n const hue = oklch.coords[2] || 0;\n\n if (hue < 30 || hue >= 330) return 'Red';\n if (hue < 60) return 'Orange';\n if (hue < 90) return 'Yellow';\n if (hue < 150) return 'Green';\n if (hue < 210) return 'Cyan';\n if (hue < 270) return 'Blue';\n if (hue < 330) return 'Purple';\n return 'Unknown';\n } catch {\n return 'Unknown';\n }\n}\n\n/**\n * Get color name with hue value\n */\nexport function getColorNameWithHue(hex: string): string {\n try {\n const color = new Color(hex);\n const oklch = color.to('oklch');\n const hue = oklch.coords[2] || 0;\n const roundedHue = Math.round(hue / 10) * 10;\n const name = getColorName(hex);\n return `${name} ${roundedHue}`;\n } catch {\n return 'Unknown';\n }\n}\n\n// Color harmony definitions\nexport const HARMONY_TYPES = [\n 'single',\n 'analogous',\n 'triad',\n 'complementary',\n 'split-complementary',\n 'square',\n 'compound',\n] as const;\nexport type HarmonyType = (typeof HARMONY_TYPES)[number];\n\nexport interface HarmonyDefinition {\n label: string;\n offsets: number[];\n primaryIndex: number;\n}\n\nexport const HARMONY_DEFINITIONS: Record<HarmonyType, HarmonyDefinition> = {\n single: {\n label: 'Single',\n offsets: [0],\n primaryIndex: 0,\n },\n analogous: {\n label: 'Analogous',\n offsets: [-30, 0, 30],\n primaryIndex: 1,\n },\n triad: {\n label: 'Triad',\n offsets: [0, 120, 240],\n primaryIndex: 0,\n },\n complementary: {\n label: 'Complementary',\n offsets: [0, 180],\n primaryIndex: 0,\n },\n 'split-complementary': {\n label: 'Split Complementary',\n offsets: [0, 150, 210],\n primaryIndex: 0,\n },\n square: {\n label: 'Square',\n offsets: [0, 90, 180, 270],\n primaryIndex: 0,\n },\n compound: {\n label: 'Compound',\n offsets: [-30, 0, 180, 210],\n primaryIndex: 1,\n },\n};\n\n// Default lightness positions (lightest to darkest)\nconst DEFAULT_LIGHTNESS_SCALE: Record<StepName, number> = {\n 50: 0.95,\n 100: 0.9,\n 200: 0.8,\n 300: 0.7,\n 400: 0.6,\n 500: 0.5,\n 600: 0.4,\n 700: 0.3,\n 800: 0.2,\n 900: 0.1,\n 950: 0.05,\n};\n\ninterface OklchColor {\n l: number;\n c: number;\n h: number;\n}\n\n/**\n * Parses an OKLCH CSS string into numerical components.\n * @param oklchString - e.g., 'oklch(50% 0.15 270)'\n * @returns Lightness (0-1), Chroma (0-~0.37), Hue (0-360)\n */\nexport function parseOklch(oklchString: string): OklchColor {\n const parts = oklchString.match(/oklch\\(([^ ]+) ([^ ]+) ([^ ]+)\\)/);\n if (!parts) throw new Error('Invalid OKLCH string format.');\n\n const [, lRaw = '', cRaw = '', hRaw = ''] = parts;\n const l = parseFloat(lRaw) / (lRaw.includes('%') ? 100 : 1);\n const c = parseFloat(cRaw);\n const h = parseFloat(hRaw);\n\n return { l, c, h };\n}\n\n/**\n * Linearly interpolates a value between a start and end point.\n */\nfunction lerp(start: number, end: number, factor: number): number {\n return start + factor * (end - start);\n}\n\n/**\n * Transpose the default lightness scale to match the provided anchors.\n */\nfunction transposeLightnessScale(\n parsedAnchors: Record<StepName, OklchColor>,\n sortedAnchorSteps: StepName[],\n): Record<StepName, number> {\n const transposedScale: Record<number, number> = {};\n\n if (sortedAnchorSteps.length === 1) {\n const anchorStep = sortedAnchorSteps[0] as StepName;\n const anchorL = (parsedAnchors[anchorStep] as OklchColor).l;\n const defaultAnchorL = DEFAULT_LIGHTNESS_SCALE[anchorStep];\n\n for (const step of STEP_NAMES) {\n if (step === anchorStep) {\n transposedScale[step] = anchorL;\n continue;\n }\n\n const defaultStepL = DEFAULT_LIGHTNESS_SCALE[step];\n\n if (defaultStepL > defaultAnchorL) {\n const factor = (defaultStepL - defaultAnchorL) / (1.0 - defaultAnchorL);\n transposedScale[step] = lerp(anchorL, 0.97, factor);\n } else {\n const factor = defaultStepL / defaultAnchorL;\n transposedScale[step] = lerp(0.05, anchorL, factor);\n }\n }\n\n return transposedScale;\n }\n\n for (const step of STEP_NAMES) {\n const anchored = parsedAnchors[step];\n if (anchored) {\n transposedScale[step] = anchored.l;\n continue;\n }\n\n let lowerStep: StepName | null = null;\n let upperStep: StepName | null = null;\n\n for (let i = sortedAnchorSteps.length - 1; i >= 0; i--) {\n const candidate = sortedAnchorSteps[i] as StepName;\n if (candidate < step) {\n lowerStep = candidate;\n break;\n }\n }\n\n for (const anchorStep of sortedAnchorSteps) {\n if (anchorStep > step) {\n upperStep = anchorStep;\n break;\n }\n }\n\n if (lowerStep !== null && upperStep !== null) {\n const lowerL = (parsedAnchors[lowerStep] as OklchColor).l;\n const upperL = (parsedAnchors[upperStep] as OklchColor).l;\n const span = upperStep - lowerStep;\n const position = step - lowerStep;\n const factor = position / span;\n transposedScale[step] = lerp(lowerL, upperL, factor);\n } else if (lowerStep !== null) {\n const lowerL = (parsedAnchors[lowerStep] as OklchColor).l;\n const defaultLowerL = DEFAULT_LIGHTNESS_SCALE[lowerStep];\n const defaultStepL = DEFAULT_LIGHTNESS_SCALE[step];\n const factor = defaultStepL / defaultLowerL;\n transposedScale[step] = lerp(0.05, lowerL, factor);\n } else if (upperStep !== null) {\n const upperL = (parsedAnchors[upperStep] as OklchColor).l;\n const defaultUpperL = DEFAULT_LIGHTNESS_SCALE[upperStep];\n const defaultStepL = DEFAULT_LIGHTNESS_SCALE[step];\n const factor = (defaultStepL - defaultUpperL) / (1.0 - defaultUpperL);\n transposedScale[step] = lerp(upperL, 0.97, factor);\n }\n }\n\n return transposedScale;\n}\n\n/**\n * Automatically assigns a color to the most appropriate step based on its lightness.\n */\nfunction assignStepByLightness(lightness: number): StepName {\n let closestStep: StepName = 500;\n let minDiff = Math.abs(lightness - DEFAULT_LIGHTNESS_SCALE[500]);\n\n for (const step of STEP_NAMES) {\n const diff = Math.abs(lightness - DEFAULT_LIGHTNESS_SCALE[step]);\n if (diff < minDiff) {\n minDiff = diff;\n closestStep = step;\n }\n }\n\n return closestStep;\n}\n\n/**\n * Generates a complete 11-step OKLCH palette from one or more colors.\n * Automatically determines which step each color belongs to based on lightness.\n */\nexport function generateOklchPalette(\n input: string | string[] | Record<string, string>,\n): Record<StepName, string> {\n let anchors: Record<number, string> = {};\n\n if (typeof input === 'string') {\n const parsed = parseOklch(input);\n const step = assignStepByLightness(parsed.l);\n anchors[step] = input;\n } else if (Array.isArray(input)) {\n for (const colorStr of input) {\n const parsed = parseOklch(colorStr);\n const step = assignStepByLightness(parsed.l);\n anchors[step] = colorStr;\n }\n } else if (typeof input === 'object') {\n anchors = input;\n } else {\n throw new Error(\n 'Input must be a color string, array of colors, or object with step assignments',\n );\n }\n\n const parsedAnchors: Record<number, OklchColor> = {};\n\n for (const key in anchors) {\n parsedAnchors[parseInt(key)] = parseOklch(anchors[key] as string);\n }\n\n const sortedAnchorSteps = Object.keys(parsedAnchors)\n .map(Number)\n .sort((a, b) => a - b) as StepName[];\n\n const lightnessScale = transposeLightnessScale(\n parsedAnchors as Record<StepName, OklchColor>,\n sortedAnchorSteps,\n );\n\n const palette: Record<number, string> = {};\n\n for (const step of STEP_NAMES) {\n if (parsedAnchors[step]) {\n palette[step] = anchors[step] as string;\n continue;\n }\n\n let startStep: StepName | null = null;\n let endStep: StepName | null = null;\n\n for (let i = sortedAnchorSteps.length - 1; i >= 0; i--) {\n const candidate = sortedAnchorSteps[i] as StepName;\n if (candidate < step) {\n startStep = candidate;\n break;\n }\n }\n\n for (const anchorStep of sortedAnchorSteps) {\n if (anchorStep > step) {\n endStep = anchorStep;\n break;\n }\n }\n\n let c_int, h_int;\n\n if (startStep !== null && endStep !== null) {\n const startColor = parsedAnchors[startStep] as OklchColor;\n const endColor = parsedAnchors[endStep] as OklchColor;\n const span = endStep - startStep;\n const position = step - startStep;\n const factor = position / span;\n\n c_int = lerp(startColor.c, endColor.c, factor);\n h_int = lerp(startColor.h, endColor.h, factor);\n } else if (startStep !== null) {\n const a = parsedAnchors[startStep] as OklchColor;\n c_int = a.c;\n h_int = a.h;\n } else if (endStep !== null) {\n const a = parsedAnchors[endStep] as OklchColor;\n c_int = a.c;\n h_int = a.h;\n } else {\n c_int = 0.1;\n h_int = 0;\n }\n\n const l_int = lightnessScale[step] as number;\n\n const dampeningFactor =\n l_int < 0.25\n ? 0.3 + (l_int / 0.25) * 0.7\n : l_int > 0.75\n ? 0.3 + ((1 - l_int) / 0.25) * 0.7\n : 1.0;\n\n c_int *= dampeningFactor;\n c_int = Math.min(c_int, 0.37);\n\n const finalL = (l_int * 100).toFixed(2) + '%';\n const finalC = c_int.toFixed(4);\n const finalH = h_int.toFixed(2);\n\n palette[step] = `oklch(${finalL} ${finalC} ${finalH})`;\n }\n\n return palette;\n}\n\n// ── Contrast + endpoints (for the functional-token layer) ────────────────────\n\n/** APCA lightness-contrast (Lc) magnitude between a foreground and background. */\nexport function contrastLc(fg: string, bg: string): number {\n return Math.abs(new Color(bg).contrast(fg, 'APCA'));\n}\n\n/**\n * Pick a tinted near-white or near-black foreground for best contrast on `bg`\n * (a whisper of the background's hue mixed into off-white/off-black).\n */\nexport function pickOn(bg: string, hue?: number): string {\n const h = hue ?? hexToOklch(bg).h;\n const white = oklchToHex({ l: 0.98, c: 0.01, h });\n const black = oklchToHex({ l: 0.16, c: 0.02, h });\n return contrastLc(white, bg) >= contrastLc(black, bg) ? white : black;\n}\n\n/**\n * The tinted off-white / off-black endpoints for a hue — white/black with a\n * whisper of the hue mixed in. These are the text/background tints every ramp\n * needs (and the one exception strict brand kits allow).\n */\nexport function tintedEndpoints(hue: number, chroma = 0.01): { light: string; dark: string } {\n return {\n light: oklchToHex({ l: 0.98, c: Math.min(chroma, 0.02), h: hue }),\n dark: oklchToHex({ l: 0.16, c: Math.min(chroma * 1.5, 0.03), h: hue }),\n };\n}\n","/**\n * Color harmony strategies for generating complementary colors\n */\n\nexport type HarmonyStrategy =\n | 'complement'\n | 'analogous-plus'\n | 'analogous-minus'\n | 'triadic-plus'\n | 'triadic-minus'\n | 'split-plus'\n | 'split-minus'\n | 'tetradic-plus'\n | 'tetradic-minus';\n\nexport interface HarmonyOption {\n id: HarmonyStrategy;\n label: string;\n description: string;\n hueShift: number;\n}\n\nexport const HARMONY_STRATEGIES: HarmonyOption[] = [\n {\n id: 'complement',\n label: 'Complement',\n description: 'Opposite on color wheel (high contrast)',\n hueShift: 180,\n },\n {\n id: 'analogous-plus',\n label: 'Analogous+',\n description: 'Adjacent colors (harmonious)',\n hueShift: 30,\n },\n {\n id: 'analogous-minus',\n label: 'Analogous-',\n description: 'Adjacent colors (harmonious)',\n hueShift: -30,\n },\n {\n id: 'triadic-plus',\n label: 'Triadic+',\n description: 'Evenly spaced (balanced)',\n hueShift: 120,\n },\n {\n id: 'triadic-minus',\n label: 'Triadic-',\n description: 'Evenly spaced (balanced)',\n hueShift: -120,\n },\n {\n id: 'split-plus',\n label: 'Split Complement+',\n description: 'Near opposite (softer contrast)',\n hueShift: 150,\n },\n {\n id: 'split-minus',\n label: 'Split Complement-',\n description: 'Near opposite (softer contrast)',\n hueShift: -150,\n },\n {\n id: 'tetradic-plus',\n label: 'Tetradic+',\n description: 'Square spacing (rich palette)',\n hueShift: 90,\n },\n {\n id: 'tetradic-minus',\n label: 'Tetradic-',\n description: 'Square spacing (rich palette)',\n hueShift: -90,\n },\n];\n\n/**\n * Applies a harmony strategy to a hue value\n */\nexport function applyHarmonyStrategy(baseHue: number, strategy: HarmonyStrategy): number {\n const harmonyOption = HARMONY_STRATEGIES.find((h) => h.id === strategy);\n if (!harmonyOption) return baseHue;\n\n let newHue = baseHue + harmonyOption.hueShift;\n\n // Normalize to 0-360 range\n while (newHue < 0) newHue += 360;\n while (newHue >= 360) newHue -= 360;\n\n return newHue;\n}\n\n/**\n * Gets all harmony suggestions for a given base hue\n */\nexport function getHarmonySuggestions(\n baseHue: number,\n): Array<{ strategy: HarmonyStrategy; hue: number; label: string; description: string }> {\n return HARMONY_STRATEGIES.map((strategy) => ({\n strategy: strategy.id,\n hue: applyHarmonyStrategy(baseHue, strategy.id),\n label: strategy.label,\n description: strategy.description,\n }));\n}\n\n/**\n * Default functional color hues (if user doesn't specify)\n */\nexport const DEFAULT_FUNCTIONAL_HUES = {\n success: 142, // Green\n warning: 38, // Orange/Amber\n error: 0, // Red\n info: 200, // Blue\n} as const;\n\n/**\n * Suggests a functional color hue based on existing palette to maintain harmony\n */\nexport function suggestFunctionalColorHue(\n type: keyof typeof DEFAULT_FUNCTIONAL_HUES,\n existingHues: number[],\n): number {\n const defaultHue = DEFAULT_FUNCTIONAL_HUES[type];\n\n if (existingHues.length === 0) {\n return defaultHue;\n }\n\n // Find the closest existing hue and adjust slightly to maintain harmony\n const avgHue = existingHues.reduce((sum, h) => sum + h, 0) / existingHues.length;\n\n // Rotate the default hue to be more in line with the palette's color temperature\n const hueShift = avgHue - 200; // Assuming 200 is neutral blue\n let adjustedHue = defaultHue + hueShift * 0.3; // 30% influence\n\n // Normalize\n while (adjustedHue < 0) adjustedHue += 360;\n while (adjustedHue >= 360) adjustedHue -= 360;\n\n return adjustedHue;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["OKLCH_Space","sRGB_Space","P3_Space"],"sources":["../../src/color/colors.ts","../../src/color/color-harmony.ts"],"sourcesContent":["import Color from 'colorjs.io';\nimport {\n OKLCH as OKLCH_Space,\n sRGB as sRGB_Space,\n P3 as P3_Space,\n ColorSpace,\n to,\n toGamutCSS,\n clone,\n serialize,\n type PlainColorObject,\n} from 'colorjs.io/fn';\n\n// Register color spaces once for functional API\nColorSpace.register(OKLCH_Space);\nColorSpace.register(sRGB_Space);\nColorSpace.register(P3_Space);\n\nexport interface RgbResult {\n r: number;\n g: number;\n b: number;\n inGamut: boolean;\n /** Max channel overshoot beyond [0,1] before clamping. 0 when in gamut. */\n gamutDistance: number;\n}\n\n/**\n * Convert OKLCh to sRGB, returning 0-255 clamped values with gamut flag.\n * Fast path for per-pixel canvas rendering (no gamut mapping, just clamp).\n */\nexport function oklchToSrgb(l: number, c: number, h: number): RgbResult {\n const col: PlainColorObject = { space: OKLCH_Space, coords: [l, c, h], alpha: 1 };\n const rgb = to(col, sRGB_Space);\n const [r, g, b] = rgb.coords;\n const inGamut = r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1;\n const gamutDistance = inGamut ? 0 : Math.max(-r, r - 1, -g, g - 1, -b, b - 1, 0);\n return {\n r: Math.max(0, Math.min(255, Math.round(r * 255))),\n g: Math.max(0, Math.min(255, Math.round(g * 255))),\n b: Math.max(0, Math.min(255, Math.round(b * 255))),\n inGamut,\n gamutDistance,\n };\n}\n\n/**\n * Convert OKLCh to Display P3, returning 0-255 clamped values with gamut flag.\n * Fast path for per-pixel canvas rendering on P3 displays.\n */\nexport function oklchToP3(l: number, c: number, h: number): RgbResult {\n const col: PlainColorObject = { space: OKLCH_Space, coords: [l, c, h], alpha: 1 };\n const rgb = to(col, P3_Space);\n const [r, g, b] = rgb.coords;\n const inGamut = r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1;\n const gamutDistance = inGamut ? 0 : Math.max(-r, r - 1, -g, g - 1, -b, b - 1, 0);\n return {\n r: Math.max(0, Math.min(255, Math.round(r * 255))),\n g: Math.max(0, Math.min(255, Math.round(g * 255))),\n b: Math.max(0, Math.min(255, Math.round(b * 255))),\n inGamut,\n gamutDistance,\n };\n}\n\n/**\n * Gamut-map an OKLCh color using the CSS gamut mapping algorithm, return hex.\n * Slower than oklchToSrgb/oklchToP3 (uses iterative reduction), use for single colors only.\n */\nexport function gamutMapOklchToHex(\n l: number,\n c: number,\n h: number,\n space: 'srgb' | 'p3' = 'srgb',\n): string {\n const col: PlainColorObject = { space: OKLCH_Space, coords: [l, c, h], alpha: 1 };\n const targetSpace = space === 'p3' ? P3_Space : sRGB_Space;\n const mapped = toGamutCSS(clone(col), { space: targetSpace });\n const rgb = to(mapped, sRGB_Space);\n return serialize(rgb, { format: 'hex' });\n}\n\n// Standard 11-step scale - will be transposed based on input anchors\nexport const STEP_NAMES = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const;\nexport type StepName = (typeof STEP_NAMES)[number];\n\nexport const COLOR_GROUPS = [\n 'neutral',\n 'brand',\n 'primary',\n 'accent',\n 'complement',\n 'success',\n 'warning',\n 'error',\n 'info',\n] as const;\nexport type ColorGroup = (typeof COLOR_GROUPS)[number];\n\n/**\n * Convert hex color to OKLCH components\n */\nexport function hexToOklch(hex: string): { l: number; c: number; h: number } {\n const color = new Color(hex);\n const oklch = color.to('oklch');\n return {\n l: oklch.coords[0],\n c: oklch.coords[1],\n h: oklch.coords[2] || 0,\n };\n}\n\n/**\n * Convert OKLCH components to hex color\n */\nexport function oklchToHex(oklch: { l: number; c: number; h: number }): string {\n const color = new Color('oklch', [oklch.l, oklch.c, oklch.h]);\n // Convert to sRGB and clamp to gamut, then format as hex\n const srgb = color.to('srgb');\n if (!srgb.inGamut()) {\n srgb.toGamut({ method: 'css' });\n }\n return srgb.toString({ format: 'hex' });\n}\n\n/**\n * Convert OKLCH CSS string to hex color\n * @example oklchStringToHex(\"oklch(50% 0.15 270)\") => \"#8b5cf6\"\n */\nexport function oklchStringToHex(oklchString: string): string {\n try {\n const color = new Color(oklchString);\n const srgb = color.to('srgb');\n if (!srgb.inGamut()) {\n srgb.toGamut({ method: 'css' });\n }\n return srgb.toString({ format: 'hex' });\n } catch {\n return '#808080';\n }\n}\n\n/**\n * Format a color name by separating compound words\n * Examples: \"mediumseagreen\" -> \"Medium Sea Green\", \"darkblue\" -> \"Dark Blue\"\n */\nexport function formatColorName(name: string): string {\n if (!name) return 'Unknown';\n\n // Handle special cases with proper word separation\n const specialCases: Record<string, string> = {\n aliceblue: 'Alice Blue',\n antiquewhite: 'Antique White',\n blanchedalmond: 'Blanched Almond',\n blueviolet: 'Blue Violet',\n burlywood: 'Burly Wood',\n cadetblue: 'Cadet Blue',\n cornflowerblue: 'Cornflower Blue',\n darkblue: 'Dark Blue',\n darkcyan: 'Dark Cyan',\n darkgoldenrod: 'Dark Goldenrod',\n darkgray: 'Dark Gray',\n darkgreen: 'Dark Green',\n darkgrey: 'Dark Grey',\n darkkhaki: 'Dark Khaki',\n darkmagenta: 'Dark Magenta',\n darkolivegreen: 'Dark Olive Green',\n darkorange: 'Dark Orange',\n darkorchid: 'Dark Orchid',\n darkred: 'Dark Red',\n darksalmon: 'Dark Salmon',\n darkseagreen: 'Dark Sea Green',\n darkslateblue: 'Dark Slate Blue',\n darkslategray: 'Dark Slate Gray',\n darkslategrey: 'Dark Slate Grey',\n darkturquoise: 'Dark Turquoise',\n darkviolet: 'Dark Violet',\n deeppink: 'Deep Pink',\n deepskyblue: 'Deep Sky Blue',\n dimgray: 'Dim Gray',\n dimgrey: 'Dim Grey',\n dodgerblue: 'Dodger Blue',\n floralwhite: 'Floral White',\n forestgreen: 'Forest Green',\n ghostwhite: 'Ghost White',\n greenyellow: 'Green Yellow',\n hotpink: 'Hot Pink',\n indianred: 'Indian Red',\n lavenderblush: 'Lavender Blush',\n lawngreen: 'Lawn Green',\n lemonchiffon: 'Lemon Chiffon',\n lightblue: 'Light Blue',\n lightcoral: 'Light Coral',\n lightcyan: 'Light Cyan',\n lightgoldenrodyellow: 'Light Goldenrod Yellow',\n lightgray: 'Light Gray',\n lightgreen: 'Light Green',\n lightgrey: 'Light Grey',\n lightpink: 'Light Pink',\n lightsalmon: 'Light Salmon',\n lightseagreen: 'Light Sea Green',\n lightskyblue: 'Light Sky Blue',\n lightslategray: 'Light Slate Gray',\n lightslategrey: 'Light Slate Grey',\n lightsteelblue: 'Light Steel Blue',\n lightyellow: 'Light Yellow',\n limegreen: 'Lime Green',\n mediumaquamarine: 'Medium Aquamarine',\n mediumblue: 'Medium Blue',\n mediumorchid: 'Medium Orchid',\n mediumpurple: 'Medium Purple',\n mediumseagreen: 'Medium Sea Green',\n mediumslateblue: 'Medium Slate Blue',\n mediumspringgreen: 'Medium Spring Green',\n mediumturquoise: 'Medium Turquoise',\n mediumvioletred: 'Medium Violet Red',\n midnightblue: 'Midnight Blue',\n mintcream: 'Mint Cream',\n mistyrose: 'Misty Rose',\n navajowhite: 'Navajo White',\n oldlace: 'Old Lace',\n olivedrab: 'Olive Drab',\n orangered: 'Orange Red',\n palegoldenrod: 'Pale Goldenrod',\n palegreen: 'Pale Green',\n paleturquoise: 'Pale Turquoise',\n palevioletred: 'Pale Violet Red',\n papayawhip: 'Papaya Whip',\n peachpuff: 'Peach Puff',\n powderblue: 'Powder Blue',\n rosybrown: 'Rosy Brown',\n royalblue: 'Royal Blue',\n saddlebrown: 'Saddle Brown',\n sandybrown: 'Sandy Brown',\n seagreen: 'Sea Green',\n skyblue: 'Sky Blue',\n slateblue: 'Slate Blue',\n slategray: 'Slate Gray',\n slategrey: 'Slate Grey',\n springgreen: 'Spring Green',\n steelblue: 'Steel Blue',\n whitesmoke: 'White Smoke',\n yellowgreen: 'Yellow Green',\n };\n\n const lowerName = name.toLowerCase();\n if (specialCases[lowerName]) {\n return specialCases[lowerName];\n }\n\n // Default: just capitalize first letter\n return name.charAt(0).toUpperCase() + name.slice(1);\n}\n\n/**\n * Get the closest CSS color name for a hex color\n */\nexport function getColorName(hex: string): string {\n try {\n const color = new Color(hex);\n const oklch = color.to('oklch');\n const hue = oklch.coords[2] || 0;\n\n if (hue < 30 || hue >= 330) return 'Red';\n if (hue < 60) return 'Orange';\n if (hue < 90) return 'Yellow';\n if (hue < 150) return 'Green';\n if (hue < 210) return 'Cyan';\n if (hue < 270) return 'Blue';\n if (hue < 330) return 'Purple';\n return 'Unknown';\n } catch {\n return 'Unknown';\n }\n}\n\n/**\n * Get color name with hue value\n */\nexport function getColorNameWithHue(hex: string): string {\n try {\n const color = new Color(hex);\n const oklch = color.to('oklch');\n const hue = oklch.coords[2] || 0;\n const roundedHue = Math.round(hue / 10) * 10;\n const name = getColorName(hex);\n return `${name} ${roundedHue}`;\n } catch {\n return 'Unknown';\n }\n}\n\n// Color harmony definitions\nexport const HARMONY_TYPES = [\n 'single',\n 'analogous',\n 'triad',\n 'complementary',\n 'split-complementary',\n 'square',\n 'compound',\n] as const;\nexport type HarmonyType = (typeof HARMONY_TYPES)[number];\n\nexport interface HarmonyDefinition {\n label: string;\n offsets: number[];\n primaryIndex: number;\n}\n\nexport const HARMONY_DEFINITIONS: Record<HarmonyType, HarmonyDefinition> = {\n single: {\n label: 'Single',\n offsets: [0],\n primaryIndex: 0,\n },\n analogous: {\n label: 'Analogous',\n offsets: [-30, 0, 30],\n primaryIndex: 1,\n },\n triad: {\n label: 'Triad',\n offsets: [0, 120, 240],\n primaryIndex: 0,\n },\n complementary: {\n label: 'Complementary',\n offsets: [0, 180],\n primaryIndex: 0,\n },\n 'split-complementary': {\n label: 'Split Complementary',\n offsets: [0, 150, 210],\n primaryIndex: 0,\n },\n square: {\n label: 'Square',\n offsets: [0, 90, 180, 270],\n primaryIndex: 0,\n },\n compound: {\n label: 'Compound',\n offsets: [-30, 0, 180, 210],\n primaryIndex: 1,\n },\n};\n\n/**\n * The shared lightness ladder every ramp is built on (lightest → darkest).\n *\n * Fixed, NOT seed-derived. Two hues at the same step have to read equally light,\n * otherwise one contrast table cannot serve every hue and a `muted` variant means\n * something different depending on which role you ask. Only chroma and hue vary\n * between ramps.\n *\n * The previous engine transposed this curve onto each seed, which let relative\n * luminance at step 300 range from 0.253 (rust) to 0.384 (amber) across the\n * shipped palette — the drift this replaces.\n *\n * Anchored steps are the one deliberate exception: see `generateOklchPalette`.\n */\nexport const LIGHTNESS_LADDER: Record<StepName, number> = {\n 50: 0.98,\n 100: 0.95,\n 200: 0.9,\n 300: 0.83,\n 400: 0.74,\n 500: 0.65,\n 600: 0.54,\n 700: 0.47,\n 800: 0.38,\n 900: 0.29,\n 950: 0.21,\n};\n\n/**\n * Chroma a ramp decays to beyond its outermost anchors, so the near-white and\n * near-black ends keep a whisper of the hue instead of going flat grey. The dark\n * end carries slightly more because chroma reads weaker against black.\n */\nexport const ENDPOINT_CHROMA = { light: 0.008, dark: 0.015 } as const;\n\ninterface OklchColor {\n l: number;\n c: number;\n h: number;\n}\n\n/**\n * Parses an OKLCH CSS string into numerical components.\n * @param oklchString - e.g., 'oklch(50% 0.15 270)'\n * @returns Lightness (0-1), Chroma (0-~0.37), Hue (0-360)\n */\nexport function parseOklch(oklchString: string): OklchColor {\n const parts = oklchString.match(/oklch\\(([^ ]+) ([^ ]+) ([^ ]+)\\)/);\n if (!parts) throw new Error('Invalid OKLCH string format.');\n\n const [, lRaw = '', cRaw = '', hRaw = ''] = parts;\n const l = parseFloat(lRaw) / (lRaw.includes('%') ? 100 : 1);\n const c = parseFloat(cRaw);\n const h = parseFloat(hRaw);\n\n return { l, c, h };\n}\n\n/**\n * Linearly interpolates a value between a start and end point.\n */\nfunction lerp(start: number, end: number, factor: number): number {\n return start + factor * (end - start);\n}\n\n/**\n * Interpolate hue the short way round the wheel. A ramp anchored at 350° and 10°\n * spans 20°, not 340° — the naive lerp sent it the long way through cyan.\n */\nfunction lerpHue(start: number, end: number, factor: number): number {\n const delta = ((((end - start) % 360) + 540) % 360) - 180;\n return (start + delta * factor + 360) % 360;\n}\n\n/**\n * The ladder step whose lightness is closest to `lightness` — i.e. where a\n * supplied colour naturally belongs.\n */\nexport function assignStepByLightness(lightness: number): StepName {\n let closestStep: StepName = 500;\n let minDiff = Math.abs(lightness - LIGHTNESS_LADDER[500]);\n\n for (const step of STEP_NAMES) {\n const diff = Math.abs(lightness - LIGHTNESS_LADDER[step]);\n if (diff < minDiff) {\n minDiff = diff;\n closestStep = step;\n }\n }\n\n return closestStep;\n}\n\n/**\n * How far an anchored colour sits from its step's ladder lightness.\n *\n * The generator surfaces this as a warning: a large deviation is legal (the\n * caller asked for that exact colour) but it means the hue will read heavier or\n * lighter than its siblings at that step, which is worth knowing rather than\n * discovering later.\n */\nexport function ladderDeviation(step: StepName, lightness: number): number {\n return lightness - LIGHTNESS_LADDER[step];\n}\n\n/** Absolute chroma ceiling — beyond this nothing survives gamut mapping anyway. */\nconst MAX_CHROMA = 0.37;\n\n/**\n * Build a complete 11-step OKLCH ramp from one or more anchor colours.\n *\n * **Ladder-first with exact anchors.** Every anchor is reproduced *verbatim* at\n * its step; every other step takes its lightness from `LIGHTNESS_LADDER`, with\n * chroma and hue interpolated between the flanking anchors and decayed toward\n * `ENDPOINT_CHROMA` beyond the outermost ones.\n *\n * The consequence is the point: a client's brand hex survives byte-for-byte,\n * while the other ten steps stay directly comparable to every other hue. The\n * deviation from the ladder is bounded and *local to anchored steps* — unlike\n * the previous engine, which warped the whole ramp to fit its anchors so every\n * step drifted.\n *\n * Chroma may come out beyond the sRGB gamut here; that is deliberate.\n * `oklchStringToHex` gamut-maps with the CSS algorithm, which reduces chroma\n * while holding lightness, so the ladder survives the conversion.\n */\nexport function generateOklchPalette(\n input: string | string[] | Record<string, string>,\n): Record<StepName, string> {\n let anchors: Record<number, string> = {};\n\n if (typeof input === 'string') {\n anchors[assignStepByLightness(parseOklch(input).l)] = input;\n } else if (Array.isArray(input)) {\n for (const colorStr of input) {\n anchors[assignStepByLightness(parseOklch(colorStr).l)] = colorStr;\n }\n } else if (typeof input === 'object' && input !== null) {\n anchors = { ...input };\n } else {\n throw new Error(\n 'Input must be a color string, array of colors, or object with step assignments',\n );\n }\n\n const parsedAnchors: Record<number, OklchColor> = {};\n for (const [key, value] of Object.entries(anchors)) {\n parsedAnchors[Number(key)] = parseOklch(value);\n }\n\n const anchorSteps = Object.keys(parsedAnchors)\n .map(Number)\n .sort((a, b) => a - b) as StepName[];\n\n // Interpolate across step *index*, not the numeric label: the labels aren't\n // evenly spaced (50→100 is a smaller jump than 100→200), so lerping on them\n // would bunch the ramp up at the light end.\n const idx = (step: number) => STEP_NAMES.indexOf(step as StepName);\n const lastIdx = STEP_NAMES.length - 1;\n\n const palette: Record<number, string> = {};\n\n for (const step of STEP_NAMES) {\n // An anchor is the caller's exact colour. Emit it untouched.\n if (parsedAnchors[step]) {\n palette[step] = anchors[step] as string;\n continue;\n }\n\n // `lighter` is the nearest anchor with a smaller step (50 is lightest);\n // `darker` the nearest with a larger one.\n const lighter = [...anchorSteps].reverse().find((s) => s < step);\n const darker = anchorSteps.find((s) => s > step);\n\n let chroma: number;\n let hue: number;\n\n if (lighter !== undefined && darker !== undefined) {\n const a = parsedAnchors[lighter] as OklchColor;\n const b = parsedAnchors[darker] as OklchColor;\n const factor = (idx(step) - idx(lighter)) / (idx(darker) - idx(lighter));\n chroma = lerp(a.c, b.c, factor);\n hue = lerpHue(a.h, b.h, factor);\n } else if (lighter !== undefined) {\n // Past the darkest anchor — fade toward the tinted near-black end.\n const a = parsedAnchors[lighter] as OklchColor;\n const factor = (idx(step) - idx(lighter)) / (lastIdx - idx(lighter));\n chroma = lerp(a.c, ENDPOINT_CHROMA.dark, factor);\n hue = a.h;\n } else if (darker !== undefined) {\n // Past the lightest anchor — fade toward the tinted near-white end.\n const b = parsedAnchors[darker] as OklchColor;\n const factor = (idx(darker) - idx(step)) / idx(darker);\n chroma = lerp(b.c, ENDPOINT_CHROMA.light, factor);\n hue = b.h;\n } else {\n chroma = 0.1;\n hue = 0;\n }\n\n const lightness = LIGHTNESS_LADDER[step];\n const finalL = (lightness * 100).toFixed(2) + '%';\n const finalC = Math.min(chroma, MAX_CHROMA).toFixed(4);\n const finalH = hue.toFixed(2);\n\n palette[step] = `oklch(${finalL} ${finalC} ${finalH})`;\n }\n\n return palette;\n}\n\n// ── Contrast + endpoints (for the functional-token layer) ────────────────────\n\n/** APCA lightness-contrast (Lc) magnitude between a foreground and background. */\nexport function contrastLc(fg: string, bg: string): number {\n return Math.abs(new Color(bg).contrast(fg, 'APCA'));\n}\n\n/**\n * Pick a tinted near-white or near-black foreground for best contrast on `bg`\n * (a whisper of the background's hue mixed into off-white/off-black).\n */\nexport function pickOn(bg: string, hue?: number): string {\n const h = hue ?? hexToOklch(bg).h;\n const white = oklchToHex({ l: 0.98, c: 0.01, h });\n const black = oklchToHex({ l: 0.16, c: 0.02, h });\n return contrastLc(white, bg) >= contrastLc(black, bg) ? white : black;\n}\n\n/**\n * The tinted off-white / off-black endpoints for a hue — white/black with a\n * whisper of the hue mixed in. These are the text/background tints every ramp\n * needs (and the one exception strict brand kits allow).\n *\n * Derived from `LIGHTNESS_LADDER` and `ENDPOINT_CHROMA` rather than its own\n * literals, so a strict tone kit's endpoints land on the same ladder rungs a\n * generated ramp would have used. This is the single definition — callers must\n * not hand-write their own near-white/near-black.\n */\nexport function tintedEndpoints(hue: number, chroma?: number): { light: string; dark: string } {\n return {\n light: oklchToHex({\n l: LIGHTNESS_LADDER[50],\n c: Math.min(chroma ?? ENDPOINT_CHROMA.light, 0.02),\n h: hue,\n }),\n dark: oklchToHex({\n l: LIGHTNESS_LADDER[950],\n c: Math.min((chroma ?? ENDPOINT_CHROMA.dark) * 1.5, 0.03),\n h: hue,\n }),\n };\n}\n","/**\n * Color harmony strategies for generating complementary colors\n */\n\nexport type HarmonyStrategy =\n | 'complement'\n | 'analogous-plus'\n | 'analogous-minus'\n | 'triadic-plus'\n | 'triadic-minus'\n | 'split-plus'\n | 'split-minus'\n | 'tetradic-plus'\n | 'tetradic-minus';\n\nexport interface HarmonyOption {\n id: HarmonyStrategy;\n label: string;\n description: string;\n hueShift: number;\n}\n\nexport const HARMONY_STRATEGIES: HarmonyOption[] = [\n {\n id: 'complement',\n label: 'Complement',\n description: 'Opposite on color wheel (high contrast)',\n hueShift: 180,\n },\n {\n id: 'analogous-plus',\n label: 'Analogous+',\n description: 'Adjacent colors (harmonious)',\n hueShift: 30,\n },\n {\n id: 'analogous-minus',\n label: 'Analogous-',\n description: 'Adjacent colors (harmonious)',\n hueShift: -30,\n },\n {\n id: 'triadic-plus',\n label: 'Triadic+',\n description: 'Evenly spaced (balanced)',\n hueShift: 120,\n },\n {\n id: 'triadic-minus',\n label: 'Triadic-',\n description: 'Evenly spaced (balanced)',\n hueShift: -120,\n },\n {\n id: 'split-plus',\n label: 'Split Complement+',\n description: 'Near opposite (softer contrast)',\n hueShift: 150,\n },\n {\n id: 'split-minus',\n label: 'Split Complement-',\n description: 'Near opposite (softer contrast)',\n hueShift: -150,\n },\n {\n id: 'tetradic-plus',\n label: 'Tetradic+',\n description: 'Square spacing (rich palette)',\n hueShift: 90,\n },\n {\n id: 'tetradic-minus',\n label: 'Tetradic-',\n description: 'Square spacing (rich palette)',\n hueShift: -90,\n },\n];\n\n/**\n * Applies a harmony strategy to a hue value\n */\nexport function applyHarmonyStrategy(baseHue: number, strategy: HarmonyStrategy): number {\n const harmonyOption = HARMONY_STRATEGIES.find((h) => h.id === strategy);\n if (!harmonyOption) return baseHue;\n\n let newHue = baseHue + harmonyOption.hueShift;\n\n // Normalize to 0-360 range\n while (newHue < 0) newHue += 360;\n while (newHue >= 360) newHue -= 360;\n\n return newHue;\n}\n\n/**\n * Gets all harmony suggestions for a given base hue\n */\nexport function getHarmonySuggestions(\n baseHue: number,\n): Array<{ strategy: HarmonyStrategy; hue: number; label: string; description: string }> {\n return HARMONY_STRATEGIES.map((strategy) => ({\n strategy: strategy.id,\n hue: applyHarmonyStrategy(baseHue, strategy.id),\n label: strategy.label,\n description: strategy.description,\n }));\n}\n\n/**\n * Default functional color hues (if user doesn't specify)\n */\nexport const DEFAULT_FUNCTIONAL_HUES = {\n success: 142, // Green\n warning: 38, // Orange/Amber\n error: 0, // Red\n info: 200, // Blue\n} as const;\n\n/**\n * Suggests a functional color hue based on existing palette to maintain harmony\n */\nexport function suggestFunctionalColorHue(\n type: keyof typeof DEFAULT_FUNCTIONAL_HUES,\n existingHues: number[],\n): number {\n const defaultHue = DEFAULT_FUNCTIONAL_HUES[type];\n\n if (existingHues.length === 0) {\n return defaultHue;\n }\n\n // Find the closest existing hue and adjust slightly to maintain harmony\n const avgHue = existingHues.reduce((sum, h) => sum + h, 0) / existingHues.length;\n\n // Rotate the default hue to be more in line with the palette's color temperature\n const hueShift = avgHue - 200; // Assuming 200 is neutral blue\n let adjustedHue = defaultHue + hueShift * 0.3; // 30% influence\n\n // Normalize\n while (adjustedHue < 0) adjustedHue += 360;\n while (adjustedHue >= 360) adjustedHue -= 360;\n\n return adjustedHue;\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -209,10 +209,15 @@ declare function organizationGraph(options: OrganizationGraphOptions): Record<st
|
|
|
209
209
|
* Keys are functional/semantic names (what the icon means).
|
|
210
210
|
* Values are the actual icon names in each set.
|
|
211
211
|
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
212
|
+
* Two consumers:
|
|
213
|
+
* - `generateIconInclude()` (below) — build time. Turns the semantic names a project
|
|
214
|
+
* declares into the `include` map astro-icon needs, so the icon set can be swapped
|
|
215
|
+
* without touching call sites.
|
|
216
|
+
* - `<wc-icon-picker>` (@getvitops/core) — browser. Its `semantic` mode lists these
|
|
217
|
+
* keys so an icon can be chosen by meaning rather than by set-specific name.
|
|
218
|
+
*
|
|
219
|
+
* `resolveIcon`/`resolveBrandIcon` map one semantic name to a fully-qualified
|
|
220
|
+
* `prefix:name` string for a given set.
|
|
216
221
|
*/
|
|
217
222
|
/**
|
|
218
223
|
* Maps astro-icon prefixes to iconMap lookup keys.
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/content.ts","../src/html.ts","../src/schema/article.ts","../src/schema/breadcrumb.ts","../src/schema/faq.ts","../src/schema/organization.ts","../src/icons.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/content.ts","../src/html.ts","../src/schema/article.ts","../src/schema/breadcrumb.ts","../src/schema/faq.ts","../src/schema/organization.ts","../src/icons.ts"],"mappings":";;;;;;;;AAWA;;;;KAAY,WAAA,YAAuB,MAAM;AAMzC;;;;AAAA,UAAiB,KAAA;EACf,KAAA;EAAA,CACC,IAAY;AAAA;;UAIE,QAAA;EACf,GAAA;EACA,GAAA,GAAM,WAAW;EAAA,CAChB,GAAA;AAAA;AAAW;AAAA,UAIG,QAAA;EACf,KAAA,EAAO,WAAA;EACP,IAAA;EACA,KAAA,GAAQ,KAAK;EAAA,CACZ,GAAA;AAAA;;UAIc,SAAA;EACf,KAAA,EAAO,QAAA;EACP,IAAA;EACA,KAAA,GAAQ,KAAK;EAAA,CACZ,GAAA;AAAA;;KAIS,IAAA,GAAO,QAAA,GAAW,SAAS;;;;;UAMtB,KAAA;EACf,IAAA;EACA,GAAA,GAAM,GAAA;EACN,KAAA,GAAQ,KAAA;EACR,OAAA,GAAU,CAAA;EAAA,CACT,GAAA;AAAA;;;AAXoC;AAMvC;KAYY,WAAA;EAGN,GAAA;EACA,KAAA,GAAQ,KAAA;EACR,IAAA,GAAO,WAAA;EACP,QAAA,GAAW,WAAA;AAAA;AAAA,iBAKD,OAAA,gCAAuC,IAAA,QAAY,IAAA,IAAQ,KAAA,CAAM,CAAA,EAAG,GAAA;AAAA,iBAIpE,MAAA,CAAO,IAAA,QAAY,IAAA,IAAQ,IAAI;AAAA,iBAI/B,UAAA,CAAW,IAAA,QAAY,IAAA,IAAQ,QAAQ;AAAA,iBAIvC,WAAA,CAAY,IAAA,QAAY,IAAA,IAAQ,SAAS;;;;;iBAUzC,CAAA,CAAE,KAAA,EAAO,WAAW,cAAc,MAAA,UAAgB,aAAA;;;;AAxCpD;iBAoDE,SAAA,CACd,OAAA;EAAW,KAAA,GAAQ,KAAA;EAAO,KAAA,GAAQ,MAAA,SAAe,KAAA;AAAA,eACjD,IAAA,WACC,KAAA;;;KCxGS,SAAA,GAAY,uBAAA,CAAwB,SAAS;AAAA,iBAEzC,kBAAA,CAAmB,IAAA,WAAe,SAAS;AAAA,iBAI3C,YAAA,CAAa,IAAA,EAAM,SAAS,EAAE,QAAA;AAAA,iBAQ9B,SAAA,CAAU,KAAA,EAAO,SAAA,GAAY,SAAS;;KAOjD,WAAA,GAAc,MAAM;AAAA,KACb,UAAA,YAAsB,WAAW;AAAA,KACjC,SAAA,GAAY,UAAA,GAAa,UAAU;;iBAe/B,SAAA,IAAa,MAAA,EAAQ,SAAS;;UAmB7B,EAAA;EACf,IAAA;EACA,GAAA,EAAK,GAAA;EACL,UAAA,GAAa,MAAM;AAAA;AD1CP;AAAA,iBCsEE,MAAA,qBAA2B,OAAA,WAAkB,EAAE,CAAC,GAAA;;iBAkDhD,WAAA,CACd,KAAA,EAAO,WAAA,IACP,WAAA,IAAc,KAAA,EAAO,WAAW;;;UCpJjB,aAAA;EACf,IAAA;EACA,GAAG;AAAA;AAAA,UAGY,mBAAA;EACf,QAAA;EACA,WAAA;EACA,KAAA;EACA,aAAA;EACA,YAAA;EACA,MAAA,EAAQ,aAAA,GAAgB,aAAa;EACrC,SAAA;IACE,IAAA;IACA,IAAA;EAAA;EAEF,gBAAA;EACA,cAAA;EACA,SAAA;EACA,QAAA;AAAA;;iBAIc,YAAA,CAAa,OAAA,EAAS,mBAAA,GAAsB,MAAM;;;UCvBjD,cAAA;EACf,IAAA;EACA,GAAG;AAAA;AAAA,UAGY,sBAAA;EACf,KAAA,EAAO,cAAc;AAAA;;iBAIP,eAAA,CAAgB,OAAA,EAAS,sBAAA,GAAyB,MAAM;;;UCVvD,OAAA;EACf,QAAA;EACA,MAAM;AAAA;AAAA,UAGS,eAAA;EACf,KAAA,EAAO,OAAO;AAAA;;AJKyB;AAMzC;;;;iBIFgB,QAAA,CAAS,OAAA,EAAS,eAAA,GAAkB,MAAM;;;UCfzC,wBAAA;EACf,IAAA;EACA,GAAA;EACA,IAAA;EACA,WAAA;EACA,KAAA;EACA,SAAA;EACA,OAAA;IACE,aAAA;IACA,eAAA;IACA,aAAA;IACA,UAAA;IACA,cAAA;EAAA;EAEF,MAAA;EACA,YAAA;EACA,QAAA;EACA,iBAAA;IAA+B,QAAA;IAAkB,QAAA;EAAA;EACjD,kBAAA;IACE,IAAA;IACA,GAAA;EAAA;EAEF,eAAA;IACE,IAAA;IACA,GAAA;EAAA;EAEF,YAAA;IACE,IAAA;IACA,SAAA;IACA,KAAA;IACA,WAAA;IACA,iBAAA;IACA,UAAA;EAAA;EAEF,UAAA;EACA,KAAA;EACA,KAAA;EACA,QAAA;IACE,IAAA;IACA,GAAA;EAAA;AAAA;;iBAKY,iBAAA,CAAkB,OAAA,EAAS,wBAAA,GAA2B,MAAM;;;;;;;ALjC5E;;;;AAAyC;AAMzC;;;;AAEe;AAIf;;;;;;;cMDa,cAAA,EAAgB,MAAM;AAAA,cAWtB,OAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyaD,OAAA,gBAAuB,OAAO;AAAA,KAC9B,YAAA,iBAA6B,OAAO;AAAA,KACpC,SAAA,iBAA0B,OAAO;;;;;;;;iBAS7B,WAAA,CAAY,IAAA,UAAc,MAAc;;AD9ajD;AAKP;;;;;iBC8bgB,gBAAA,CAAiB,IAAA,UAAc,MAAc;;;AD9be;;;;ACtB5E;;;;AAAmC;AAWnC;;iBAiegB,mBAAA,CAAoB,WAAA;EAClC,EAAA;EACA,KAAA;EACA,QAAA;EAAA,CACC,MAAA;AAAA,IACC,MAAM"}
|
package/dist/index.mjs
CHANGED
|
@@ -304,10 +304,15 @@ function organizationGraph(options) {
|
|
|
304
304
|
* Keys are functional/semantic names (what the icon means).
|
|
305
305
|
* Values are the actual icon names in each set.
|
|
306
306
|
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
307
|
+
* Two consumers:
|
|
308
|
+
* - `generateIconInclude()` (below) — build time. Turns the semantic names a project
|
|
309
|
+
* declares into the `include` map astro-icon needs, so the icon set can be swapped
|
|
310
|
+
* without touching call sites.
|
|
311
|
+
* - `<wc-icon-picker>` (@getvitops/core) — browser. Its `semantic` mode lists these
|
|
312
|
+
* keys so an icon can be chosen by meaning rather than by set-specific name.
|
|
313
|
+
*
|
|
314
|
+
* `resolveIcon`/`resolveBrandIcon` map one semantic name to a fully-qualified
|
|
315
|
+
* `prefix:name` string for a given set.
|
|
311
316
|
*/
|
|
312
317
|
/**
|
|
313
318
|
* Maps astro-icon prefixes to iconMap lookup keys.
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["s"],"sources":["../src/content.ts","../src/html.ts","../src/schema/article.ts","../src/schema/breadcrumb.ts","../src/schema/faq.ts","../src/schema/organization.ts","../src/icons.ts"],"sourcesContent":["/**\n * Framework-agnostic content-model types, guards, i18n, and part-attr resolution.\n *\n * Extracted from @getvitops/astro so the pure-TS helpers live in one place (no\n * Astro dependency). The Astro-typed element tag was `astro/types`' `HTMLTag`;\n * here it's a plain `string` (any tag name), keeping these fully framework-neutral.\n */\n\n// ── content-model types ──────────────────────────────────────────────────────\n\n/** A translatable value: a plain string, or a locale → string map. */\nexport type Localizable = string | Record<string, string>;\n\n/**\n * An HTML attribute bag. `class` may be a string or a class:list-style array\n * (falsy entries dropped); everything else is passed through to the element.\n */\nexport interface Attrs {\n class?: string | (string | false | null | undefined)[];\n [attr: string]: unknown;\n}\n\n/** An image reference used by image links. */\nexport interface ImageRef {\n src: string;\n alt?: Localizable;\n [key: string]: unknown;\n}\n\n/** A link with a text label. */\nexport interface TextLink {\n label: Localizable;\n href: string;\n attrs?: Attrs;\n [key: string]: unknown;\n}\n\n/** A link whose content is an image. */\nexport interface ImageLink {\n image: ImageRef;\n href: string;\n attrs?: Attrs;\n [key: string]: unknown;\n}\n\n/** Any link — text or image. */\nexport type Link = TextLink | ImageLink;\n\n/**\n * A generic content element wrapper (discriminated by `type: 'element'`),\n * carrying a payload `T` rendered as `Tag` (any HTML tag name).\n */\nexport interface Elmnt<T = unknown, Tag extends string = 'div'> {\n type: 'element';\n tag?: Tag;\n attrs?: Attrs;\n content?: T;\n [key: string]: unknown;\n}\n\n/**\n * A renderable node tree — a text string (Localizable) or an element with\n * optional attrs and either `text` shorthand or `children`.\n */\nexport type ContentNode =\n | string\n | {\n tag: string;\n attrs?: Attrs;\n text?: Localizable;\n children?: ContentNode[];\n };\n\n// ── type guards ──────────────────────────────────────────────────────────────\n\nexport function isElmnt<T, Tag extends string = 'div'>(item: any): item is Elmnt<T, Tag> {\n return item && item.type === 'element';\n}\n\nexport function isLink(item: any): item is Link {\n return item && ('label' in item || 'image' in item) && 'href' in item;\n}\n\nexport function isTextLink(item: any): item is TextLink {\n return item && 'label' in item && 'href' in item;\n}\n\nexport function isImageLink(item: any): item is ImageLink {\n return item && 'image' in item && 'href' in item;\n}\n\n// ── i18n ─────────────────────────────────────────────────────────────────────\n\n/**\n * Resolve a Localizable value to a string for the given locale. A plain string\n * is returned as-is; a locale map returns the best match (locale → default → '').\n */\nexport function t(value: Localizable | undefined, locale: string, defaultLocale: string): string {\n if (value == null) return '';\n if (typeof value === 'string') return value;\n return value[locale] ?? value[defaultLocale] ?? '';\n}\n\n// ── part-attr resolution ─────────────────────────────────────────────────────\n\n/**\n * Resolve per-part attrs from a presentation-type config. For the `root` part,\n * merges legacy `attrs` with `parts.root` (backward compat).\n */\nexport function partAttrs(\n present: { attrs?: Attrs; parts?: Record<string, Attrs> } | undefined,\n part: string,\n): Attrs {\n const fromParts = present?.parts?.[part];\n if (part === 'root') {\n const legacy = present?.attrs;\n if (!legacy && !fromParts) return {};\n const { class: lc, ...lr } = legacy ?? {};\n const { class: pc, ...pr } = fromParts ?? {};\n const classes = [lc, pc].flat().filter((c): c is string => typeof c === 'string' && c !== '');\n return {\n ...(classes.length ? { class: classes } : {}),\n ...lr,\n ...pr,\n };\n }\n return fromParts ?? {};\n}\n","/**\n * Framework-agnostic HTML/markup helpers (parse5-based). Extracted from\n * @getvitops/astro — no Astro runtime dependency; the Astro-typed `HTMLTag` /\n * `HTMLAttributes` are generalized to `string` / `Record<string, unknown>`.\n */\nimport { parseFragment, serialize as s, type DefaultTreeAdapterTypes } from 'parse5';\nimport type { Localizable, ContentNode } from './content.ts';\n\nexport type ChildNode = DefaultTreeAdapterTypes.ChildNode;\n\nexport function parseRenderedSlots(html: string): ChildNode[] {\n return parseFragment(html).childNodes;\n}\n\nexport function getAttribute(node: ChildNode, attrName: string): string | null {\n if ('attrs' in node) {\n const attr = node.attrs.find((a) => a.name === attrName);\n return attr ? attr.value : null;\n }\n return null;\n}\n\nexport function serialize(nodes: ChildNode | ChildNode[]): string[] {\n return (Array.isArray(nodes) ? nodes : [nodes]).map((node) =>\n s(node as DefaultTreeAdapterTypes.ParentNode),\n );\n}\n\n/** Style value types that can be combined (camelCase or --custom-prop keys). */\ntype StyleObject = Record<string, string | number | null | undefined>;\nexport type StyleValue = string | StyleObject | null | undefined;\nexport type StyleList = StyleValue | StyleValue[];\n\n/** camelCase → kebab-case, preserving CSS custom properties (`--var-name`). */\nfunction toKebabCase(str: string): string {\n if (str.startsWith('--')) return str;\n return str.replace(/([A-Z])/g, '-$1').toLowerCase();\n}\nfunction styleObjectToString(obj: StyleObject): string {\n return Object.entries(obj)\n .filter(([, value]) => value != null)\n .map(([key, value]) => `${toKebabCase(key)}: ${value}`)\n .join('; ');\n}\n\n/** Combine multiple style formats into one CSS string (like `class:list` for styles). */\nexport function styleList(...styles: StyleList[]): string {\n const result: string[] = [];\n const process = (item: StyleList): void => {\n if (item == null) return;\n if (Array.isArray(item)) {\n item.forEach(process);\n } else if (typeof item === 'string') {\n const trimmed = item.trim();\n if (trimmed) result.push(trimmed);\n } else {\n const str = styleObjectToString(item as StyleObject);\n if (str) result.push(str);\n }\n };\n styles.forEach(process);\n return result.join('; ');\n}\n\n/** Element descriptor: a tag name, text content, and optional attributes. */\nexport interface El<Tag extends string = string> {\n text: string;\n tag: Tag;\n attributes?: Record<string, unknown>;\n}\n\nfunction isEl(value: string | El): value is El {\n return typeof value === 'object' && value !== null && 'tag' in value && 'text' in value;\n}\n\nfunction attributesToString(attrs: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(attrs)) {\n if (value == null || value === false) continue;\n if (value === true) {\n parts.push(key);\n } else if (key === 'style' && typeof value === 'object') {\n parts.push(`style=\"${styleList(value as StyleValue)}\"`);\n } else {\n const text = Array.isArray(value)\n ? value.filter((v): v is string => typeof v === 'string' && v !== '').join(' ')\n : typeof value === 'object'\n ? JSON.stringify(value)\n : String(value as string | number | boolean);\n parts.push(`${key}=\"${text.replace(/\"/g, '"')}\"`);\n }\n }\n return parts.join(' ');\n}\n\n/** Normalize a string or `El` object into an HTML string (for `set:html`). */\nexport function toHtml<Tag extends string>(content: string | El<Tag>): string {\n if (!isEl(content)) return content;\n const { tag, text, attributes } = content;\n const attrStr = attributes ? attributesToString(attributes) : '';\n const t = String(tag);\n return attrStr ? `<${t} ${attrStr}>${text}</${t}>` : `<${t}>${text}</${t}>`;\n}\n\n// ── node-tree renderer — { tag, attrs, children } ────────────────────────────\nconst VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\nfunction defaultResolveText(value: Localizable): string {\n if (typeof value === 'string') return value;\n const values = Object.values(value);\n return values[0] ?? '';\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\nfunction nodeToHtml(node: ContentNode, resolveText: (value: Localizable) => string): string {\n if (typeof node === 'string') return escapeHtml(resolveText(node));\n const { tag, attrs, text, children } = node;\n const attrStr = attrs ? attributesToString(attrs) : '';\n const open = attrStr ? `<${tag} ${attrStr}>` : `<${tag}>`;\n if (VOID_ELEMENTS.has(tag)) return open;\n let inner = '';\n if (text != null) inner = escapeHtml(resolveText(text));\n else if (children?.length)\n inner = children.map((child) => nodeToHtml(child, resolveText)).join('');\n return `${open}${inner}</${tag}>`;\n}\n\n/** Render an array of `ContentNode`s to an HTML string. */\nexport function nodesToHtml(\n nodes: ContentNode[],\n resolveText: (value: Localizable) => string = defaultResolveText,\n): string {\n return nodes.map((node) => nodeToHtml(node, resolveText)).join('');\n}\n","export interface ArticleAuthor {\n name: string;\n url?: string;\n}\n\nexport interface ArticleGraphOptions {\n headline: string;\n description?: string;\n image?: string | string[];\n datePublished: string;\n dateModified?: string;\n author: ArticleAuthor | ArticleAuthor[];\n publisher?: {\n name: string;\n logo?: string;\n };\n mainEntityOfPage?: string;\n articleSection?: string;\n wordCount?: number;\n keywords?: string[];\n}\n\n/** Build a schema.org Article JSON-LD graph. */\nexport function articleGraph(options: ArticleGraphOptions): Record<string, unknown> {\n const {\n headline,\n description,\n image,\n datePublished,\n dateModified,\n author,\n publisher,\n mainEntityOfPage,\n articleSection,\n wordCount,\n keywords,\n } = options;\n\n const authors = Array.isArray(author) ? author : [author];\n\n return {\n '@context': 'https://schema.org',\n '@type': 'Article',\n headline,\n ...(description && { description }),\n ...(image && { image: Array.isArray(image) ? image : [image] }),\n datePublished,\n ...(dateModified && { dateModified }),\n author: authors.map((a) => ({\n '@type': 'Person',\n name: a.name,\n ...(a.url && { url: a.url }),\n })),\n ...(publisher && {\n publisher: {\n '@type': 'Organization',\n name: publisher.name,\n ...(publisher.logo && { logo: { '@type': 'ImageObject', url: publisher.logo } }),\n },\n }),\n ...(mainEntityOfPage && { mainEntityOfPage: { '@type': 'WebPage', '@id': mainEntityOfPage } }),\n ...(articleSection && { articleSection }),\n ...(wordCount && { wordCount }),\n ...(keywords && { keywords: keywords.join(', ') }),\n };\n}\n","export interface BreadcrumbItem {\n name: string;\n url: string;\n}\n\nexport interface BreadcrumbGraphOptions {\n items: BreadcrumbItem[];\n}\n\n/** Build a schema.org BreadcrumbList JSON-LD graph. */\nexport function breadcrumbGraph(options: BreadcrumbGraphOptions): Record<string, unknown> {\n return {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: options.items.map((item, index) => ({\n '@type': 'ListItem',\n position: index + 1,\n name: item.name,\n item: item.url,\n })),\n };\n}\n","export interface FAQItem {\n question: string;\n answer: string;\n}\n\nexport interface FAQGraphOptions {\n items: FAQItem[];\n}\n\n/**\n * Build a schema.org FAQPage JSON-LD graph.\n *\n * NOTE: Google recommends FAQ markup only for authoritative government\n * and health sites. For other sites, consider using QAPage schema instead.\n */\nexport function faqGraph(options: FAQGraphOptions): Record<string, unknown> {\n return {\n '@context': 'https://schema.org',\n '@type': 'FAQPage',\n mainEntity: options.items.map((item) => ({\n '@type': 'Question',\n name: item.question,\n acceptedAnswer: {\n '@type': 'Answer',\n text: item.answer,\n },\n })),\n };\n}\n","export interface OrganizationGraphOptions {\n name: string;\n url?: string;\n logo?: string;\n description?: string;\n email?: string;\n telephone?: string;\n address?: {\n streetAddress?: string;\n addressLocality?: string;\n addressRegion?: string;\n postalCode?: string;\n addressCountry?: string;\n };\n sameAs?: string[];\n foundingDate?: string;\n founders?: string[];\n numberOfEmployees?: number | { minValue: number; maxValue: number };\n parentOrganization?: {\n name: string;\n url?: string;\n };\n subOrganization?: {\n name: string;\n url?: string;\n }[];\n contactPoint?: {\n type?: 'customer service' | 'technical support' | 'sales' | 'billing support' | 'reservations';\n telephone: string;\n email?: string;\n contactType: string;\n availableLanguage?: string[];\n areaServed?: string[];\n }[];\n areaServed?: string[];\n brand?: string;\n award?: string[];\n memberOf?: {\n name: string;\n url?: string;\n }[];\n}\n\n/** Build a schema.org Organization JSON-LD graph. */\nexport function organizationGraph(options: OrganizationGraphOptions): Record<string, unknown> {\n const {\n name,\n url,\n logo,\n description,\n email,\n telephone,\n address,\n sameAs,\n foundingDate,\n founders,\n numberOfEmployees,\n parentOrganization,\n subOrganization,\n contactPoint,\n areaServed,\n brand,\n award,\n memberOf,\n } = options;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'Organization',\n name,\n ...(url && { url }),\n ...(logo && { logo }),\n ...(description && { description }),\n ...(email && { email }),\n ...(telephone && { telephone }),\n ...(address && {\n address: {\n '@type': 'PostalAddress',\n ...(address.streetAddress && { streetAddress: address.streetAddress }),\n ...(address.addressLocality && { addressLocality: address.addressLocality }),\n ...(address.addressRegion && { addressRegion: address.addressRegion }),\n ...(address.postalCode && { postalCode: address.postalCode }),\n ...(address.addressCountry && { addressCountry: address.addressCountry }),\n },\n }),\n ...(sameAs && { sameAs }),\n ...(foundingDate && { foundingDate }),\n ...(founders && {\n founders: founders.map((f) => ({\n '@type': 'Person',\n name: f,\n })),\n }),\n ...(numberOfEmployees && {\n numberOfEmployees:\n typeof numberOfEmployees === 'number'\n ? { '@type': 'QuantitativeValue', value: numberOfEmployees }\n : {\n '@type': 'QuantitativeValue',\n minValue: numberOfEmployees.minValue,\n maxValue: numberOfEmployees.maxValue,\n },\n }),\n ...(parentOrganization && {\n parentOrganization: {\n '@type': 'Organization',\n name: parentOrganization.name,\n ...(parentOrganization.url && { url: parentOrganization.url }),\n },\n }),\n ...(subOrganization && {\n subOrganization: subOrganization.map((sub) => ({\n '@type': 'Organization',\n name: sub.name,\n ...(sub.url && { url: sub.url }),\n })),\n }),\n ...(contactPoint && {\n contactPoint: contactPoint.map((cp) => ({\n '@type': 'ContactPoint',\n telephone: cp.telephone,\n contactType: cp.contactType,\n ...(cp.email && { email: cp.email }),\n ...(cp.availableLanguage && { availableLanguage: cp.availableLanguage }),\n ...(cp.areaServed && { areaServed: cp.areaServed }),\n })),\n }),\n ...(areaServed && { areaServed }),\n ...(brand && { brand: { '@type': 'Brand', name: brand } }),\n ...(award && { award }),\n ...(memberOf && {\n memberOf: memberOf.map((m) => ({\n '@type': 'Organization',\n name: m.name,\n ...(m.url && { url: m.url }),\n })),\n }),\n };\n}\n","/**\n * Semantic icon name mapping across icon sets.\n *\n * Keys are functional/semantic names (what the icon means).\n * Values are the actual icon names in each set.\n *\n * Usage:\n * import { icon } from '../utils/icon-resolver';\n * <Icon name={icon('save')} /> // resolves via configured UI set\n * <Icon name={icon('facebook')} /> // resolves via configured brand set\n */\n\n/**\n * Maps astro-icon prefixes to iconMap lookup keys.\n * FA7 variants (fa7-solid, fa7-regular, etc.) all share the same icon names\n * and map to the 'fa7' key. Other sets map to themselves.\n */\nexport const prefixToMapKey: Record<string, string> = {\n 'fa7-solid': 'fa7',\n 'fa7-regular': 'fa7',\n 'fa7-light': 'fa7',\n 'fa7-thin': 'fa7',\n 'fa7-brands': 'fa7-brands',\n 'simple-icons': 'simple-icons',\n 'material-symbols': 'material-symbols',\n lucide: 'lucide',\n};\n\nexport const iconMap = {\n fa7: {\n // Navigation / UI\n menu: 'bars',\n close: 'xmark',\n home: 'home',\n settings: 'gear',\n search: 'magnifying-glass',\n 'expand-more': 'chevron-down',\n 'expand-less': 'chevron-up',\n 'chevron-right': 'chevron-right',\n 'chevron-left': 'chevron-left',\n 'arrow-back': 'arrow-left',\n 'arrow-forward': 'arrow-right',\n 'external-link': 'arrow-up-right-from-square',\n 'more-vert': 'ellipsis-vertical',\n 'more-horiz': 'ellipsis',\n\n // Actions\n add: 'plus',\n remove: 'minus',\n delete: 'trash',\n edit: 'pen',\n save: 'floppy-disk',\n copy: 'copy',\n paste: 'paste',\n attach: 'paperclip',\n upload: 'upload',\n download: 'download',\n share: 'share',\n bookmark: 'bookmark',\n favorite: 'heart',\n star: 'star',\n login: 'login',\n logout: 'logout',\n\n // Communication\n email: 'envelope',\n phone: 'phone',\n location: 'location-dot',\n globe: 'globe',\n link: 'link',\n\n // Time\n clock: 'clock',\n calendar: 'calendar',\n schedule: 'calendar-days',\n\n // People\n person: 'user',\n group: 'users',\n\n // Content / Files\n file: 'file',\n 'file-add': 'file-circle-plus',\n folder: 'folder',\n 'folder-open': 'folder-open',\n 'folder-add': 'folder-plus',\n image: 'image',\n export: 'file-export',\n import: 'file-import',\n backup: 'backup',\n compress: 'compress',\n\n // Status / Feedback\n check: 'check',\n error: 'circle-exclamation',\n warning: 'triangle-exclamation',\n info: 'circle-info',\n help: 'circle-question',\n\n // Commerce\n cart: 'cart-shopping',\n tag: 'tag',\n 'credit-card': 'credit-card',\n receipt: 'receipt',\n\n // Nature (landscaping context)\n leaf: 'leaf',\n tree: 'tree',\n seedling: 'seedling',\n trowel: 'trowel',\n droplet: 'droplet',\n snowflake: 'snowflake',\n sun: 'sun',\n cloud: 'cloud',\n\n // Layout / View\n grid: 'table-cells',\n list: 'list',\n filter: 'filter',\n sort: 'sort',\n fullscreen: 'expand',\n collapse: 'compress',\n\n // Misc\n building: 'building',\n video: 'video',\n lock: 'lock',\n unlock: 'lock-open',\n eye: 'eye',\n 'eye-off': 'eye-slash',\n print: 'print',\n code: 'code',\n palette: 'palette',\n lightbulb: 'lightbulb',\n },\n\n 'fa7-brands': {\n // Social Media\n facebook: 'facebook',\n instagram: 'instagram',\n x: 'x-twitter',\n bluesky: 'bluesky',\n threads: 'threads',\n mastodon: 'mastodon',\n linkedin: 'linkedin',\n youtube: 'youtube',\n tiktok: 'tiktok',\n pinterest: 'pinterest-p',\n reddit: 'reddit',\n snapchat: 'snapchat',\n github: 'github',\n\n // Messaging\n whatsapp: 'whatsapp',\n telegram: 'telegram',\n discord: 'discord',\n\n // Payment\n stripe: 'stripe',\n paypal: 'paypal',\n visa: 'cc-visa',\n mastercard: 'cc-mastercard',\n amex: 'cc-amex',\n discover: 'cc-discover',\n 'apple-pay': 'apple-pay',\n 'google-pay': 'google-pay',\n 'amazon-pay': 'amazon-pay',\n\n // Review / Directory\n yelp: 'yelp',\n google: 'google',\n\n // Platforms\n apple: 'apple',\n microsoft: 'microsoft',\n amazon: 'amazon',\n shopify: 'shopify',\n wordpress: 'wordpress',\n cloudflare: 'cloudflare',\n },\n\n 'simple-icons': {\n // Social Media\n facebook: 'facebook',\n instagram: 'instagram',\n x: 'x',\n bluesky: 'bluesky',\n threads: 'threads',\n mastodon: 'mastodon',\n linkedin: 'linkedin',\n youtube: 'youtube',\n tiktok: 'tiktok',\n pinterest: 'pinterest',\n reddit: 'reddit',\n snapchat: 'snapchat',\n github: 'github',\n\n // Messaging\n whatsapp: 'whatsapp',\n telegram: 'telegram',\n discord: 'discord',\n\n // Payment\n stripe: 'stripe',\n paypal: 'paypal',\n visa: 'visa',\n mastercard: 'mastercard',\n amex: 'americanexpress',\n discover: 'discover',\n 'apple-pay': 'applepay',\n 'google-pay': 'googlepay',\n 'amazon-pay': 'amazonpay',\n klarna: 'klarna',\n afterpay: 'afterpay',\n square: 'square',\n cashapp: 'cashapp',\n interac: 'interac',\n\n // Review / Directory\n yelp: 'yelp',\n google: 'google',\n tripadvisor: 'tripadvisor',\n trustpilot: 'trustpilot',\n 'google-maps': 'googlemaps',\n homeadvisor: 'homeadvisor',\n houzz: 'houzz',\n nextdoor: 'nextdoor',\n bbb: 'bbb',\n\n // Platforms\n apple: 'apple',\n microsoft: 'microsoft',\n amazon: 'amazon',\n shopify: 'shopify',\n wordpress: 'wordpress',\n cloudflare: 'cloudflare',\n waze: 'waze',\n },\n\n 'material-symbols': {\n // Navigation / UI\n menu: 'menu',\n close: 'close',\n home: 'home',\n settings: 'settings',\n search: 'search',\n 'expand-more': 'expand-more',\n 'expand-less': 'expand-less',\n 'chevron-right': 'chevron-right',\n 'chevron-left': 'chevron-left',\n 'arrow-back': 'arrow-back',\n 'arrow-forward': 'arrow-forward',\n 'external-link': 'open-in-new',\n 'more-vert': 'more-vert',\n 'more-horiz': 'more-horiz',\n\n // Actions\n add: 'add',\n remove: 'remove',\n delete: 'delete',\n edit: 'edit',\n save: 'save',\n copy: 'content-copy',\n paste: 'content-paste',\n attach: 'attach-file',\n upload: 'upload',\n download: 'download',\n share: 'share',\n bookmark: 'bookmark',\n favorite: 'favorite',\n star: 'star',\n login: 'login',\n logout: 'logout',\n\n // Communication\n email: 'mail',\n phone: 'call',\n location: 'location-on',\n globe: 'language',\n link: 'link',\n\n // Time\n clock: 'schedule',\n calendar: 'calendar-today',\n schedule: 'calendar-month',\n\n // People\n person: 'person',\n group: 'group',\n\n // Content / Files\n file: 'description',\n 'file-add': 'note-add',\n folder: 'folder',\n 'folder-open': 'folder-open',\n 'folder-add': 'create-new-folder',\n image: 'image',\n export: 'upload-file',\n import: 'download',\n backup: 'backup',\n compress: 'compress',\n\n // Status / Feedback\n check: 'check-circle',\n error: 'error',\n warning: 'warning',\n info: 'info',\n help: 'help',\n\n // Commerce\n cart: 'shopping-cart',\n tag: 'sell',\n 'credit-card': 'credit-card',\n receipt: 'receipt-long',\n\n // Nature (landscaping context)\n leaf: 'eco',\n tree: 'forest',\n seedling: 'potted-plant',\n trowel: 'construction',\n droplet: 'water-drop',\n snowflake: 'ac-unit',\n sun: 'light-mode',\n cloud: 'cloud',\n\n // Layout / View\n grid: 'grid-view',\n list: 'list',\n filter: 'filter-list',\n sort: 'sort',\n fullscreen: 'fullscreen',\n collapse: 'fullscreen-exit',\n\n // Misc\n building: 'domain',\n video: 'videocam',\n lock: 'lock',\n unlock: 'lock-open',\n eye: 'visibility',\n 'eye-off': 'visibility-off',\n print: 'print',\n code: 'code',\n palette: 'palette',\n lightbulb: 'lightbulb',\n },\n lucide: {\n // Navigation / UI\n menu: 'menu',\n close: 'x',\n home: 'house',\n settings: 'settings',\n search: 'search',\n 'expand-more': 'chevron-down',\n 'expand-less': 'chevron-up',\n 'chevron-right': 'chevron-right',\n 'chevron-left': 'chevron-left',\n 'arrow-back': 'arrow-left',\n 'arrow-forward': 'arrow-right',\n 'external-link': 'external-link',\n 'more-vert': 'ellipsis-vertical',\n 'more-horiz': 'ellipsis',\n\n // Actions\n add: 'plus',\n remove: 'minus',\n delete: 'trash-2',\n edit: 'pencil',\n save: 'save',\n copy: 'copy',\n paste: 'clipboard-paste',\n attach: 'paperclip',\n upload: 'upload',\n download: 'download',\n share: 'share-2',\n bookmark: 'bookmark',\n favorite: 'heart',\n star: 'star',\n login: 'log-in',\n logout: 'log-out',\n\n // Communication\n email: 'mail',\n phone: 'phone',\n location: 'map-pin',\n globe: 'globe',\n link: 'link',\n\n // Time\n clock: 'clock',\n calendar: 'calendar',\n schedule: 'calendar-days',\n\n // People\n person: 'user',\n group: 'users',\n\n // Content / Files\n file: 'file',\n 'file-add': 'file-plus',\n folder: 'folder',\n 'folder-open': 'folder-open',\n 'folder-add': 'folder-plus',\n image: 'image',\n export: 'file-output',\n import: 'file-input',\n backup: 'hard-drive-upload',\n compress: 'minimize-2',\n\n // Status / Feedback\n check: 'check-circle',\n error: 'circle-alert',\n warning: 'triangle-alert',\n info: 'info',\n help: 'circle-help',\n\n // Commerce\n cart: 'shopping-cart',\n tag: 'tag',\n 'credit-card': 'credit-card',\n receipt: 'receipt',\n\n // Nature (landscaping context)\n leaf: 'leaf',\n tree: 'tree-pine',\n seedling: 'sprout',\n trowel: 'shovel',\n droplet: 'droplet',\n snowflake: 'snowflake',\n sun: 'sun',\n cloud: 'cloud',\n\n // Layout / View\n grid: 'layout-grid',\n list: 'list',\n filter: 'filter',\n sort: 'arrow-up-down',\n fullscreen: 'maximize',\n collapse: 'minimize',\n\n // Misc\n building: 'building-2',\n video: 'video',\n lock: 'lock',\n unlock: 'lock-open',\n eye: 'eye',\n 'eye-off': 'eye-off',\n print: 'printer',\n code: 'code',\n palette: 'palette',\n lightbulb: 'lightbulb',\n },\n} as const satisfies Record<string, Record<string, string>>;\n\nexport type IconSet = keyof typeof iconMap;\nexport type SemanticIcon = keyof (typeof iconMap)['fa7'];\nexport type BrandIcon = keyof (typeof iconMap)['simple-icons'];\n\n/**\n * Resolve a semantic icon name to a fully-qualified astro-icon string.\n * Names containing ':' are returned as-is (pass-through for fully-qualified names).\n *\n * @param name - Semantic name ('email') or fully-qualified ('fa7-solid:envelope')\n * @param prefix - astro-icon prefix, e.g. 'fa7-solid', 'material-symbols', 'lucide'\n */\nexport function resolveIcon(name: string, prefix: string): string {\n if (name.includes(':')) return name;\n const mapKey = prefixToMapKey[prefix] as IconSet | undefined;\n if (!mapKey)\n throw new Error(\n `Unknown icon prefix \"${prefix}\". Valid: ${Object.keys(prefixToMapKey).join(', ')}`,\n );\n const map = iconMap[mapKey];\n const resolved = map[name as keyof typeof map];\n if (!resolved)\n throw new Error(`Icon \"${name}\" not found in set \"${prefix}\" (map key: \"${mapKey}\")`);\n return `${prefix}:${resolved}`;\n}\n\n/**\n * Resolve a brand icon name to a fully-qualified astro-icon string.\n * Names containing ':' are returned as-is (pass-through).\n *\n * @param name - Semantic brand name ('facebook') or fully-qualified ('simple-icons:facebook')\n * @param prefix - astro-icon prefix, e.g. 'simple-icons', 'fa7-brands'\n */\nexport function resolveBrandIcon(name: string, prefix: string): string {\n if (name.includes(':')) return name;\n const mapKey = prefixToMapKey[prefix] as IconSet | undefined;\n if (!mapKey) throw new Error(`Unknown brand icon prefix \"${prefix}\"`);\n const map = iconMap[mapKey];\n const resolved = map[name as keyof typeof map];\n if (!resolved)\n throw new Error(`Brand icon \"${name}\" not found in set \"${prefix}\" (map key: \"${mapKey}\")`);\n return `${prefix}:${resolved}`;\n}\n\n/**\n * Generate the astro-icon `include` map from configured icon sets.\n *\n * Resolves two kinds of entries from the `icons` section of `site.config.yaml`:\n * - Per-set lists (e.g. `'fa7-solid': ['bars', 'plus']`) are passed through as-is.\n * - `semantic` names are looked up in the configured `ui` and `brand` prefix maps,\n * and the resolved icon names are merged into those sets' lists.\n *\n * Only explicitly configured icons are included — there is no fallback to all icons.\n *\n * @param iconsConfig - Icons config from site.config.yaml (icons section)\n * @returns Record<string, string[]> for astro-icon's `include` option\n */\nexport function generateIconInclude(iconsConfig?: {\n ui?: string;\n brand?: string;\n semantic?: string[];\n [prefix: string]: string | string[] | undefined;\n}): Record<string, string[]> {\n const uiPrefix = iconsConfig?.ui ?? 'fa7-solid';\n const brandPrefix = iconsConfig?.brand ?? 'simple-icons';\n const include: Record<string, string[]> = {};\n\n const addToInclude = (prefix: string, names: string[]) => {\n include[prefix] = [...new Set([...(include[prefix] ?? []), ...names])];\n };\n\n // Pass through per-set explicit lists directly\n for (const [key, val] of Object.entries(iconsConfig ?? {})) {\n if (key !== 'ui' && key !== 'brand' && key !== 'semantic' && Array.isArray(val)) {\n addToInclude(key, val as string[]);\n }\n }\n\n // Resolve semantic names through ui and brand prefix maps.\n const uiMapKey = prefixToMapKey[uiPrefix] as IconSet | undefined;\n const brandMapKey = prefixToMapKey[brandPrefix] as IconSet | undefined;\n const unknownPrefix: string[] = [];\n if (!uiMapKey) unknownPrefix.push(`ui: '${uiPrefix}'`);\n if (!brandMapKey) unknownPrefix.push(`brand: '${brandPrefix}'`);\n if (unknownPrefix.length)\n throw new Error(\n `[vitops icons] Unknown icon set ${unknownPrefix.join(' and ')}. ` +\n `Known sets: ${Object.keys(prefixToMapKey).join(', ')}.`,\n );\n\n const unresolved: string[] = [];\n for (const name of iconsConfig?.semantic ?? []) {\n const ui = (iconMap[uiMapKey!] as Record<string, string>)[name];\n const brand = (iconMap[brandMapKey!] as Record<string, string>)[name];\n if (ui) addToInclude(uiPrefix, [ui]);\n if (brand) addToInclude(brandPrefix, [brand]);\n if (!ui && !brand) unresolved.push(name);\n }\n\n // Fail the build rather than silently omitting the icon. Skipping quietly is\n // what makes swapping icon sets frightening: the swap \"succeeds\" and the gaps\n // only show up as missing glyphs in production.\n if (unresolved.length)\n throw new Error(\n `[vitops icons] ${unresolved.length} semantic icon name(s) not found in ` +\n `ui set '${uiPrefix}' or brand set '${brandPrefix}': ${unresolved.join(', ')}.\\n` +\n `Either add them to iconMap in @getvitops/core, or drop them from the ` +\n `\\`semantic\\` list. Available in '${uiPrefix}': ` +\n `${Object.keys(iconMap[uiMapKey!]).slice(0, 12).join(', ')}…`,\n );\n\n return include;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["s"],"sources":["../src/content.ts","../src/html.ts","../src/schema/article.ts","../src/schema/breadcrumb.ts","../src/schema/faq.ts","../src/schema/organization.ts","../src/icons.ts"],"sourcesContent":["/**\n * Framework-agnostic content-model types, guards, i18n, and part-attr resolution.\n *\n * Extracted from @getvitops/astro so the pure-TS helpers live in one place (no\n * Astro dependency). The Astro-typed element tag was `astro/types`' `HTMLTag`;\n * here it's a plain `string` (any tag name), keeping these fully framework-neutral.\n */\n\n// ── content-model types ──────────────────────────────────────────────────────\n\n/** A translatable value: a plain string, or a locale → string map. */\nexport type Localizable = string | Record<string, string>;\n\n/**\n * An HTML attribute bag. `class` may be a string or a class:list-style array\n * (falsy entries dropped); everything else is passed through to the element.\n */\nexport interface Attrs {\n class?: string | (string | false | null | undefined)[];\n [attr: string]: unknown;\n}\n\n/** An image reference used by image links. */\nexport interface ImageRef {\n src: string;\n alt?: Localizable;\n [key: string]: unknown;\n}\n\n/** A link with a text label. */\nexport interface TextLink {\n label: Localizable;\n href: string;\n attrs?: Attrs;\n [key: string]: unknown;\n}\n\n/** A link whose content is an image. */\nexport interface ImageLink {\n image: ImageRef;\n href: string;\n attrs?: Attrs;\n [key: string]: unknown;\n}\n\n/** Any link — text or image. */\nexport type Link = TextLink | ImageLink;\n\n/**\n * A generic content element wrapper (discriminated by `type: 'element'`),\n * carrying a payload `T` rendered as `Tag` (any HTML tag name).\n */\nexport interface Elmnt<T = unknown, Tag extends string = 'div'> {\n type: 'element';\n tag?: Tag;\n attrs?: Attrs;\n content?: T;\n [key: string]: unknown;\n}\n\n/**\n * A renderable node tree — a text string (Localizable) or an element with\n * optional attrs and either `text` shorthand or `children`.\n */\nexport type ContentNode =\n | string\n | {\n tag: string;\n attrs?: Attrs;\n text?: Localizable;\n children?: ContentNode[];\n };\n\n// ── type guards ──────────────────────────────────────────────────────────────\n\nexport function isElmnt<T, Tag extends string = 'div'>(item: any): item is Elmnt<T, Tag> {\n return item && item.type === 'element';\n}\n\nexport function isLink(item: any): item is Link {\n return item && ('label' in item || 'image' in item) && 'href' in item;\n}\n\nexport function isTextLink(item: any): item is TextLink {\n return item && 'label' in item && 'href' in item;\n}\n\nexport function isImageLink(item: any): item is ImageLink {\n return item && 'image' in item && 'href' in item;\n}\n\n// ── i18n ─────────────────────────────────────────────────────────────────────\n\n/**\n * Resolve a Localizable value to a string for the given locale. A plain string\n * is returned as-is; a locale map returns the best match (locale → default → '').\n */\nexport function t(value: Localizable | undefined, locale: string, defaultLocale: string): string {\n if (value == null) return '';\n if (typeof value === 'string') return value;\n return value[locale] ?? value[defaultLocale] ?? '';\n}\n\n// ── part-attr resolution ─────────────────────────────────────────────────────\n\n/**\n * Resolve per-part attrs from a presentation-type config. For the `root` part,\n * merges legacy `attrs` with `parts.root` (backward compat).\n */\nexport function partAttrs(\n present: { attrs?: Attrs; parts?: Record<string, Attrs> } | undefined,\n part: string,\n): Attrs {\n const fromParts = present?.parts?.[part];\n if (part === 'root') {\n const legacy = present?.attrs;\n if (!legacy && !fromParts) return {};\n const { class: lc, ...lr } = legacy ?? {};\n const { class: pc, ...pr } = fromParts ?? {};\n const classes = [lc, pc].flat().filter((c): c is string => typeof c === 'string' && c !== '');\n return {\n ...(classes.length ? { class: classes } : {}),\n ...lr,\n ...pr,\n };\n }\n return fromParts ?? {};\n}\n","/**\n * Framework-agnostic HTML/markup helpers (parse5-based). Extracted from\n * @getvitops/astro — no Astro runtime dependency; the Astro-typed `HTMLTag` /\n * `HTMLAttributes` are generalized to `string` / `Record<string, unknown>`.\n */\nimport { parseFragment, serialize as s, type DefaultTreeAdapterTypes } from 'parse5';\nimport type { Localizable, ContentNode } from './content.ts';\n\nexport type ChildNode = DefaultTreeAdapterTypes.ChildNode;\n\nexport function parseRenderedSlots(html: string): ChildNode[] {\n return parseFragment(html).childNodes;\n}\n\nexport function getAttribute(node: ChildNode, attrName: string): string | null {\n if ('attrs' in node) {\n const attr = node.attrs.find((a) => a.name === attrName);\n return attr ? attr.value : null;\n }\n return null;\n}\n\nexport function serialize(nodes: ChildNode | ChildNode[]): string[] {\n return (Array.isArray(nodes) ? nodes : [nodes]).map((node) =>\n s(node as DefaultTreeAdapterTypes.ParentNode),\n );\n}\n\n/** Style value types that can be combined (camelCase or --custom-prop keys). */\ntype StyleObject = Record<string, string | number | null | undefined>;\nexport type StyleValue = string | StyleObject | null | undefined;\nexport type StyleList = StyleValue | StyleValue[];\n\n/** camelCase → kebab-case, preserving CSS custom properties (`--var-name`). */\nfunction toKebabCase(str: string): string {\n if (str.startsWith('--')) return str;\n return str.replace(/([A-Z])/g, '-$1').toLowerCase();\n}\nfunction styleObjectToString(obj: StyleObject): string {\n return Object.entries(obj)\n .filter(([, value]) => value != null)\n .map(([key, value]) => `${toKebabCase(key)}: ${value}`)\n .join('; ');\n}\n\n/** Combine multiple style formats into one CSS string (like `class:list` for styles). */\nexport function styleList(...styles: StyleList[]): string {\n const result: string[] = [];\n const process = (item: StyleList): void => {\n if (item == null) return;\n if (Array.isArray(item)) {\n item.forEach(process);\n } else if (typeof item === 'string') {\n const trimmed = item.trim();\n if (trimmed) result.push(trimmed);\n } else {\n const str = styleObjectToString(item as StyleObject);\n if (str) result.push(str);\n }\n };\n styles.forEach(process);\n return result.join('; ');\n}\n\n/** Element descriptor: a tag name, text content, and optional attributes. */\nexport interface El<Tag extends string = string> {\n text: string;\n tag: Tag;\n attributes?: Record<string, unknown>;\n}\n\nfunction isEl(value: string | El): value is El {\n return typeof value === 'object' && value !== null && 'tag' in value && 'text' in value;\n}\n\nfunction attributesToString(attrs: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(attrs)) {\n if (value == null || value === false) continue;\n if (value === true) {\n parts.push(key);\n } else if (key === 'style' && typeof value === 'object') {\n parts.push(`style=\"${styleList(value as StyleValue)}\"`);\n } else {\n const text = Array.isArray(value)\n ? value.filter((v): v is string => typeof v === 'string' && v !== '').join(' ')\n : typeof value === 'object'\n ? JSON.stringify(value)\n : String(value as string | number | boolean);\n parts.push(`${key}=\"${text.replace(/\"/g, '"')}\"`);\n }\n }\n return parts.join(' ');\n}\n\n/** Normalize a string or `El` object into an HTML string (for `set:html`). */\nexport function toHtml<Tag extends string>(content: string | El<Tag>): string {\n if (!isEl(content)) return content;\n const { tag, text, attributes } = content;\n const attrStr = attributes ? attributesToString(attributes) : '';\n const t = String(tag);\n return attrStr ? `<${t} ${attrStr}>${text}</${t}>` : `<${t}>${text}</${t}>`;\n}\n\n// ── node-tree renderer — { tag, attrs, children } ────────────────────────────\nconst VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\nfunction defaultResolveText(value: Localizable): string {\n if (typeof value === 'string') return value;\n const values = Object.values(value);\n return values[0] ?? '';\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\nfunction nodeToHtml(node: ContentNode, resolveText: (value: Localizable) => string): string {\n if (typeof node === 'string') return escapeHtml(resolveText(node));\n const { tag, attrs, text, children } = node;\n const attrStr = attrs ? attributesToString(attrs) : '';\n const open = attrStr ? `<${tag} ${attrStr}>` : `<${tag}>`;\n if (VOID_ELEMENTS.has(tag)) return open;\n let inner = '';\n if (text != null) inner = escapeHtml(resolveText(text));\n else if (children?.length)\n inner = children.map((child) => nodeToHtml(child, resolveText)).join('');\n return `${open}${inner}</${tag}>`;\n}\n\n/** Render an array of `ContentNode`s to an HTML string. */\nexport function nodesToHtml(\n nodes: ContentNode[],\n resolveText: (value: Localizable) => string = defaultResolveText,\n): string {\n return nodes.map((node) => nodeToHtml(node, resolveText)).join('');\n}\n","export interface ArticleAuthor {\n name: string;\n url?: string;\n}\n\nexport interface ArticleGraphOptions {\n headline: string;\n description?: string;\n image?: string | string[];\n datePublished: string;\n dateModified?: string;\n author: ArticleAuthor | ArticleAuthor[];\n publisher?: {\n name: string;\n logo?: string;\n };\n mainEntityOfPage?: string;\n articleSection?: string;\n wordCount?: number;\n keywords?: string[];\n}\n\n/** Build a schema.org Article JSON-LD graph. */\nexport function articleGraph(options: ArticleGraphOptions): Record<string, unknown> {\n const {\n headline,\n description,\n image,\n datePublished,\n dateModified,\n author,\n publisher,\n mainEntityOfPage,\n articleSection,\n wordCount,\n keywords,\n } = options;\n\n const authors = Array.isArray(author) ? author : [author];\n\n return {\n '@context': 'https://schema.org',\n '@type': 'Article',\n headline,\n ...(description && { description }),\n ...(image && { image: Array.isArray(image) ? image : [image] }),\n datePublished,\n ...(dateModified && { dateModified }),\n author: authors.map((a) => ({\n '@type': 'Person',\n name: a.name,\n ...(a.url && { url: a.url }),\n })),\n ...(publisher && {\n publisher: {\n '@type': 'Organization',\n name: publisher.name,\n ...(publisher.logo && { logo: { '@type': 'ImageObject', url: publisher.logo } }),\n },\n }),\n ...(mainEntityOfPage && { mainEntityOfPage: { '@type': 'WebPage', '@id': mainEntityOfPage } }),\n ...(articleSection && { articleSection }),\n ...(wordCount && { wordCount }),\n ...(keywords && { keywords: keywords.join(', ') }),\n };\n}\n","export interface BreadcrumbItem {\n name: string;\n url: string;\n}\n\nexport interface BreadcrumbGraphOptions {\n items: BreadcrumbItem[];\n}\n\n/** Build a schema.org BreadcrumbList JSON-LD graph. */\nexport function breadcrumbGraph(options: BreadcrumbGraphOptions): Record<string, unknown> {\n return {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: options.items.map((item, index) => ({\n '@type': 'ListItem',\n position: index + 1,\n name: item.name,\n item: item.url,\n })),\n };\n}\n","export interface FAQItem {\n question: string;\n answer: string;\n}\n\nexport interface FAQGraphOptions {\n items: FAQItem[];\n}\n\n/**\n * Build a schema.org FAQPage JSON-LD graph.\n *\n * NOTE: Google recommends FAQ markup only for authoritative government\n * and health sites. For other sites, consider using QAPage schema instead.\n */\nexport function faqGraph(options: FAQGraphOptions): Record<string, unknown> {\n return {\n '@context': 'https://schema.org',\n '@type': 'FAQPage',\n mainEntity: options.items.map((item) => ({\n '@type': 'Question',\n name: item.question,\n acceptedAnswer: {\n '@type': 'Answer',\n text: item.answer,\n },\n })),\n };\n}\n","export interface OrganizationGraphOptions {\n name: string;\n url?: string;\n logo?: string;\n description?: string;\n email?: string;\n telephone?: string;\n address?: {\n streetAddress?: string;\n addressLocality?: string;\n addressRegion?: string;\n postalCode?: string;\n addressCountry?: string;\n };\n sameAs?: string[];\n foundingDate?: string;\n founders?: string[];\n numberOfEmployees?: number | { minValue: number; maxValue: number };\n parentOrganization?: {\n name: string;\n url?: string;\n };\n subOrganization?: {\n name: string;\n url?: string;\n }[];\n contactPoint?: {\n type?: 'customer service' | 'technical support' | 'sales' | 'billing support' | 'reservations';\n telephone: string;\n email?: string;\n contactType: string;\n availableLanguage?: string[];\n areaServed?: string[];\n }[];\n areaServed?: string[];\n brand?: string;\n award?: string[];\n memberOf?: {\n name: string;\n url?: string;\n }[];\n}\n\n/** Build a schema.org Organization JSON-LD graph. */\nexport function organizationGraph(options: OrganizationGraphOptions): Record<string, unknown> {\n const {\n name,\n url,\n logo,\n description,\n email,\n telephone,\n address,\n sameAs,\n foundingDate,\n founders,\n numberOfEmployees,\n parentOrganization,\n subOrganization,\n contactPoint,\n areaServed,\n brand,\n award,\n memberOf,\n } = options;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'Organization',\n name,\n ...(url && { url }),\n ...(logo && { logo }),\n ...(description && { description }),\n ...(email && { email }),\n ...(telephone && { telephone }),\n ...(address && {\n address: {\n '@type': 'PostalAddress',\n ...(address.streetAddress && { streetAddress: address.streetAddress }),\n ...(address.addressLocality && { addressLocality: address.addressLocality }),\n ...(address.addressRegion && { addressRegion: address.addressRegion }),\n ...(address.postalCode && { postalCode: address.postalCode }),\n ...(address.addressCountry && { addressCountry: address.addressCountry }),\n },\n }),\n ...(sameAs && { sameAs }),\n ...(foundingDate && { foundingDate }),\n ...(founders && {\n founders: founders.map((f) => ({\n '@type': 'Person',\n name: f,\n })),\n }),\n ...(numberOfEmployees && {\n numberOfEmployees:\n typeof numberOfEmployees === 'number'\n ? { '@type': 'QuantitativeValue', value: numberOfEmployees }\n : {\n '@type': 'QuantitativeValue',\n minValue: numberOfEmployees.minValue,\n maxValue: numberOfEmployees.maxValue,\n },\n }),\n ...(parentOrganization && {\n parentOrganization: {\n '@type': 'Organization',\n name: parentOrganization.name,\n ...(parentOrganization.url && { url: parentOrganization.url }),\n },\n }),\n ...(subOrganization && {\n subOrganization: subOrganization.map((sub) => ({\n '@type': 'Organization',\n name: sub.name,\n ...(sub.url && { url: sub.url }),\n })),\n }),\n ...(contactPoint && {\n contactPoint: contactPoint.map((cp) => ({\n '@type': 'ContactPoint',\n telephone: cp.telephone,\n contactType: cp.contactType,\n ...(cp.email && { email: cp.email }),\n ...(cp.availableLanguage && { availableLanguage: cp.availableLanguage }),\n ...(cp.areaServed && { areaServed: cp.areaServed }),\n })),\n }),\n ...(areaServed && { areaServed }),\n ...(brand && { brand: { '@type': 'Brand', name: brand } }),\n ...(award && { award }),\n ...(memberOf && {\n memberOf: memberOf.map((m) => ({\n '@type': 'Organization',\n name: m.name,\n ...(m.url && { url: m.url }),\n })),\n }),\n };\n}\n","/**\n * Semantic icon name mapping across icon sets.\n *\n * Keys are functional/semantic names (what the icon means).\n * Values are the actual icon names in each set.\n *\n * Two consumers:\n * - `generateIconInclude()` (below) — build time. Turns the semantic names a project\n * declares into the `include` map astro-icon needs, so the icon set can be swapped\n * without touching call sites.\n * - `<wc-icon-picker>` (@getvitops/core) — browser. Its `semantic` mode lists these\n * keys so an icon can be chosen by meaning rather than by set-specific name.\n *\n * `resolveIcon`/`resolveBrandIcon` map one semantic name to a fully-qualified\n * `prefix:name` string for a given set.\n */\n\n/**\n * Maps astro-icon prefixes to iconMap lookup keys.\n * FA7 variants (fa7-solid, fa7-regular, etc.) all share the same icon names\n * and map to the 'fa7' key. Other sets map to themselves.\n */\nexport const prefixToMapKey: Record<string, string> = {\n 'fa7-solid': 'fa7',\n 'fa7-regular': 'fa7',\n 'fa7-light': 'fa7',\n 'fa7-thin': 'fa7',\n 'fa7-brands': 'fa7-brands',\n 'simple-icons': 'simple-icons',\n 'material-symbols': 'material-symbols',\n lucide: 'lucide',\n};\n\nexport const iconMap = {\n fa7: {\n // Navigation / UI\n menu: 'bars',\n close: 'xmark',\n home: 'home',\n settings: 'gear',\n search: 'magnifying-glass',\n 'expand-more': 'chevron-down',\n 'expand-less': 'chevron-up',\n 'chevron-right': 'chevron-right',\n 'chevron-left': 'chevron-left',\n 'arrow-back': 'arrow-left',\n 'arrow-forward': 'arrow-right',\n 'external-link': 'arrow-up-right-from-square',\n 'more-vert': 'ellipsis-vertical',\n 'more-horiz': 'ellipsis',\n\n // Actions\n add: 'plus',\n remove: 'minus',\n delete: 'trash',\n edit: 'pen',\n save: 'floppy-disk',\n copy: 'copy',\n paste: 'paste',\n attach: 'paperclip',\n upload: 'upload',\n download: 'download',\n share: 'share',\n bookmark: 'bookmark',\n favorite: 'heart',\n star: 'star',\n login: 'login',\n logout: 'logout',\n\n // Communication\n email: 'envelope',\n phone: 'phone',\n location: 'location-dot',\n globe: 'globe',\n link: 'link',\n\n // Time\n clock: 'clock',\n calendar: 'calendar',\n schedule: 'calendar-days',\n\n // People\n person: 'user',\n group: 'users',\n\n // Content / Files\n file: 'file',\n 'file-add': 'file-circle-plus',\n folder: 'folder',\n 'folder-open': 'folder-open',\n 'folder-add': 'folder-plus',\n image: 'image',\n export: 'file-export',\n import: 'file-import',\n backup: 'backup',\n compress: 'compress',\n\n // Status / Feedback\n check: 'check',\n error: 'circle-exclamation',\n warning: 'triangle-exclamation',\n info: 'circle-info',\n help: 'circle-question',\n\n // Commerce\n cart: 'cart-shopping',\n tag: 'tag',\n 'credit-card': 'credit-card',\n receipt: 'receipt',\n\n // Nature (landscaping context)\n leaf: 'leaf',\n tree: 'tree',\n seedling: 'seedling',\n trowel: 'trowel',\n droplet: 'droplet',\n snowflake: 'snowflake',\n sun: 'sun',\n cloud: 'cloud',\n\n // Layout / View\n grid: 'table-cells',\n list: 'list',\n filter: 'filter',\n sort: 'sort',\n fullscreen: 'expand',\n collapse: 'compress',\n\n // Misc\n building: 'building',\n video: 'video',\n lock: 'lock',\n unlock: 'lock-open',\n eye: 'eye',\n 'eye-off': 'eye-slash',\n print: 'print',\n code: 'code',\n palette: 'palette',\n lightbulb: 'lightbulb',\n },\n\n 'fa7-brands': {\n // Social Media\n facebook: 'facebook',\n instagram: 'instagram',\n x: 'x-twitter',\n bluesky: 'bluesky',\n threads: 'threads',\n mastodon: 'mastodon',\n linkedin: 'linkedin',\n youtube: 'youtube',\n tiktok: 'tiktok',\n pinterest: 'pinterest-p',\n reddit: 'reddit',\n snapchat: 'snapchat',\n github: 'github',\n\n // Messaging\n whatsapp: 'whatsapp',\n telegram: 'telegram',\n discord: 'discord',\n\n // Payment\n stripe: 'stripe',\n paypal: 'paypal',\n visa: 'cc-visa',\n mastercard: 'cc-mastercard',\n amex: 'cc-amex',\n discover: 'cc-discover',\n 'apple-pay': 'apple-pay',\n 'google-pay': 'google-pay',\n 'amazon-pay': 'amazon-pay',\n\n // Review / Directory\n yelp: 'yelp',\n google: 'google',\n\n // Platforms\n apple: 'apple',\n microsoft: 'microsoft',\n amazon: 'amazon',\n shopify: 'shopify',\n wordpress: 'wordpress',\n cloudflare: 'cloudflare',\n },\n\n 'simple-icons': {\n // Social Media\n facebook: 'facebook',\n instagram: 'instagram',\n x: 'x',\n bluesky: 'bluesky',\n threads: 'threads',\n mastodon: 'mastodon',\n linkedin: 'linkedin',\n youtube: 'youtube',\n tiktok: 'tiktok',\n pinterest: 'pinterest',\n reddit: 'reddit',\n snapchat: 'snapchat',\n github: 'github',\n\n // Messaging\n whatsapp: 'whatsapp',\n telegram: 'telegram',\n discord: 'discord',\n\n // Payment\n stripe: 'stripe',\n paypal: 'paypal',\n visa: 'visa',\n mastercard: 'mastercard',\n amex: 'americanexpress',\n discover: 'discover',\n 'apple-pay': 'applepay',\n 'google-pay': 'googlepay',\n 'amazon-pay': 'amazonpay',\n klarna: 'klarna',\n afterpay: 'afterpay',\n square: 'square',\n cashapp: 'cashapp',\n interac: 'interac',\n\n // Review / Directory\n yelp: 'yelp',\n google: 'google',\n tripadvisor: 'tripadvisor',\n trustpilot: 'trustpilot',\n 'google-maps': 'googlemaps',\n homeadvisor: 'homeadvisor',\n houzz: 'houzz',\n nextdoor: 'nextdoor',\n bbb: 'bbb',\n\n // Platforms\n apple: 'apple',\n microsoft: 'microsoft',\n amazon: 'amazon',\n shopify: 'shopify',\n wordpress: 'wordpress',\n cloudflare: 'cloudflare',\n waze: 'waze',\n },\n\n 'material-symbols': {\n // Navigation / UI\n menu: 'menu',\n close: 'close',\n home: 'home',\n settings: 'settings',\n search: 'search',\n 'expand-more': 'expand-more',\n 'expand-less': 'expand-less',\n 'chevron-right': 'chevron-right',\n 'chevron-left': 'chevron-left',\n 'arrow-back': 'arrow-back',\n 'arrow-forward': 'arrow-forward',\n 'external-link': 'open-in-new',\n 'more-vert': 'more-vert',\n 'more-horiz': 'more-horiz',\n\n // Actions\n add: 'add',\n remove: 'remove',\n delete: 'delete',\n edit: 'edit',\n save: 'save',\n copy: 'content-copy',\n paste: 'content-paste',\n attach: 'attach-file',\n upload: 'upload',\n download: 'download',\n share: 'share',\n bookmark: 'bookmark',\n favorite: 'favorite',\n star: 'star',\n login: 'login',\n logout: 'logout',\n\n // Communication\n email: 'mail',\n phone: 'call',\n location: 'location-on',\n globe: 'language',\n link: 'link',\n\n // Time\n clock: 'schedule',\n calendar: 'calendar-today',\n schedule: 'calendar-month',\n\n // People\n person: 'person',\n group: 'group',\n\n // Content / Files\n file: 'description',\n 'file-add': 'note-add',\n folder: 'folder',\n 'folder-open': 'folder-open',\n 'folder-add': 'create-new-folder',\n image: 'image',\n export: 'upload-file',\n import: 'download',\n backup: 'backup',\n compress: 'compress',\n\n // Status / Feedback\n check: 'check-circle',\n error: 'error',\n warning: 'warning',\n info: 'info',\n help: 'help',\n\n // Commerce\n cart: 'shopping-cart',\n tag: 'sell',\n 'credit-card': 'credit-card',\n receipt: 'receipt-long',\n\n // Nature (landscaping context)\n leaf: 'eco',\n tree: 'forest',\n seedling: 'potted-plant',\n trowel: 'construction',\n droplet: 'water-drop',\n snowflake: 'ac-unit',\n sun: 'light-mode',\n cloud: 'cloud',\n\n // Layout / View\n grid: 'grid-view',\n list: 'list',\n filter: 'filter-list',\n sort: 'sort',\n fullscreen: 'fullscreen',\n collapse: 'fullscreen-exit',\n\n // Misc\n building: 'domain',\n video: 'videocam',\n lock: 'lock',\n unlock: 'lock-open',\n eye: 'visibility',\n 'eye-off': 'visibility-off',\n print: 'print',\n code: 'code',\n palette: 'palette',\n lightbulb: 'lightbulb',\n },\n lucide: {\n // Navigation / UI\n menu: 'menu',\n close: 'x',\n home: 'house',\n settings: 'settings',\n search: 'search',\n 'expand-more': 'chevron-down',\n 'expand-less': 'chevron-up',\n 'chevron-right': 'chevron-right',\n 'chevron-left': 'chevron-left',\n 'arrow-back': 'arrow-left',\n 'arrow-forward': 'arrow-right',\n 'external-link': 'external-link',\n 'more-vert': 'ellipsis-vertical',\n 'more-horiz': 'ellipsis',\n\n // Actions\n add: 'plus',\n remove: 'minus',\n delete: 'trash-2',\n edit: 'pencil',\n save: 'save',\n copy: 'copy',\n paste: 'clipboard-paste',\n attach: 'paperclip',\n upload: 'upload',\n download: 'download',\n share: 'share-2',\n bookmark: 'bookmark',\n favorite: 'heart',\n star: 'star',\n login: 'log-in',\n logout: 'log-out',\n\n // Communication\n email: 'mail',\n phone: 'phone',\n location: 'map-pin',\n globe: 'globe',\n link: 'link',\n\n // Time\n clock: 'clock',\n calendar: 'calendar',\n schedule: 'calendar-days',\n\n // People\n person: 'user',\n group: 'users',\n\n // Content / Files\n file: 'file',\n 'file-add': 'file-plus',\n folder: 'folder',\n 'folder-open': 'folder-open',\n 'folder-add': 'folder-plus',\n image: 'image',\n export: 'file-output',\n import: 'file-input',\n backup: 'hard-drive-upload',\n compress: 'minimize-2',\n\n // Status / Feedback\n check: 'check-circle',\n error: 'circle-alert',\n warning: 'triangle-alert',\n info: 'info',\n help: 'circle-help',\n\n // Commerce\n cart: 'shopping-cart',\n tag: 'tag',\n 'credit-card': 'credit-card',\n receipt: 'receipt',\n\n // Nature (landscaping context)\n leaf: 'leaf',\n tree: 'tree-pine',\n seedling: 'sprout',\n trowel: 'shovel',\n droplet: 'droplet',\n snowflake: 'snowflake',\n sun: 'sun',\n cloud: 'cloud',\n\n // Layout / View\n grid: 'layout-grid',\n list: 'list',\n filter: 'filter',\n sort: 'arrow-up-down',\n fullscreen: 'maximize',\n collapse: 'minimize',\n\n // Misc\n building: 'building-2',\n video: 'video',\n lock: 'lock',\n unlock: 'lock-open',\n eye: 'eye',\n 'eye-off': 'eye-off',\n print: 'printer',\n code: 'code',\n palette: 'palette',\n lightbulb: 'lightbulb',\n },\n} as const satisfies Record<string, Record<string, string>>;\n\nexport type IconSet = keyof typeof iconMap;\nexport type SemanticIcon = keyof (typeof iconMap)['fa7'];\nexport type BrandIcon = keyof (typeof iconMap)['simple-icons'];\n\n/**\n * Resolve a semantic icon name to a fully-qualified astro-icon string.\n * Names containing ':' are returned as-is (pass-through for fully-qualified names).\n *\n * @param name - Semantic name ('email') or fully-qualified ('fa7-solid:envelope')\n * @param prefix - astro-icon prefix, e.g. 'fa7-solid', 'material-symbols', 'lucide'\n */\nexport function resolveIcon(name: string, prefix: string): string {\n if (name.includes(':')) return name;\n const mapKey = prefixToMapKey[prefix] as IconSet | undefined;\n if (!mapKey)\n throw new Error(\n `Unknown icon prefix \"${prefix}\". Valid: ${Object.keys(prefixToMapKey).join(', ')}`,\n );\n const map = iconMap[mapKey];\n const resolved = map[name as keyof typeof map];\n if (!resolved)\n throw new Error(`Icon \"${name}\" not found in set \"${prefix}\" (map key: \"${mapKey}\")`);\n return `${prefix}:${resolved}`;\n}\n\n/**\n * Resolve a brand icon name to a fully-qualified astro-icon string.\n * Names containing ':' are returned as-is (pass-through).\n *\n * @param name - Semantic brand name ('facebook') or fully-qualified ('simple-icons:facebook')\n * @param prefix - astro-icon prefix, e.g. 'simple-icons', 'fa7-brands'\n */\nexport function resolveBrandIcon(name: string, prefix: string): string {\n if (name.includes(':')) return name;\n const mapKey = prefixToMapKey[prefix] as IconSet | undefined;\n if (!mapKey) throw new Error(`Unknown brand icon prefix \"${prefix}\"`);\n const map = iconMap[mapKey];\n const resolved = map[name as keyof typeof map];\n if (!resolved)\n throw new Error(`Brand icon \"${name}\" not found in set \"${prefix}\" (map key: \"${mapKey}\")`);\n return `${prefix}:${resolved}`;\n}\n\n/**\n * Generate the astro-icon `include` map from configured icon sets.\n *\n * Resolves two kinds of entries from the `icons` section of `site.config.yaml`:\n * - Per-set lists (e.g. `'fa7-solid': ['bars', 'plus']`) are passed through as-is.\n * - `semantic` names are looked up in the configured `ui` and `brand` prefix maps,\n * and the resolved icon names are merged into those sets' lists.\n *\n * Only explicitly configured icons are included — there is no fallback to all icons.\n *\n * @param iconsConfig - Icons config from site.config.yaml (icons section)\n * @returns Record<string, string[]> for astro-icon's `include` option\n */\nexport function generateIconInclude(iconsConfig?: {\n ui?: string;\n brand?: string;\n semantic?: string[];\n [prefix: string]: string | string[] | undefined;\n}): Record<string, string[]> {\n const uiPrefix = iconsConfig?.ui ?? 'fa7-solid';\n const brandPrefix = iconsConfig?.brand ?? 'simple-icons';\n const include: Record<string, string[]> = {};\n\n const addToInclude = (prefix: string, names: string[]) => {\n include[prefix] = [...new Set([...(include[prefix] ?? []), ...names])];\n };\n\n // Pass through per-set explicit lists directly\n for (const [key, val] of Object.entries(iconsConfig ?? {})) {\n if (key !== 'ui' && key !== 'brand' && key !== 'semantic' && Array.isArray(val)) {\n addToInclude(key, val as string[]);\n }\n }\n\n // Resolve semantic names through ui and brand prefix maps.\n const uiMapKey = prefixToMapKey[uiPrefix] as IconSet | undefined;\n const brandMapKey = prefixToMapKey[brandPrefix] as IconSet | undefined;\n const unknownPrefix: string[] = [];\n if (!uiMapKey) unknownPrefix.push(`ui: '${uiPrefix}'`);\n if (!brandMapKey) unknownPrefix.push(`brand: '${brandPrefix}'`);\n if (unknownPrefix.length)\n throw new Error(\n `[vitops icons] Unknown icon set ${unknownPrefix.join(' and ')}. ` +\n `Known sets: ${Object.keys(prefixToMapKey).join(', ')}.`,\n );\n\n const unresolved: string[] = [];\n for (const name of iconsConfig?.semantic ?? []) {\n const ui = (iconMap[uiMapKey!] as Record<string, string>)[name];\n const brand = (iconMap[brandMapKey!] as Record<string, string>)[name];\n if (ui) addToInclude(uiPrefix, [ui]);\n if (brand) addToInclude(brandPrefix, [brand]);\n if (!ui && !brand) unresolved.push(name);\n }\n\n // Fail the build rather than silently omitting the icon. Skipping quietly is\n // what makes swapping icon sets frightening: the swap \"succeeds\" and the gaps\n // only show up as missing glyphs in production.\n if (unresolved.length)\n throw new Error(\n `[vitops icons] ${unresolved.length} semantic icon name(s) not found in ` +\n `ui set '${uiPrefix}' or brand set '${brandPrefix}': ${unresolved.join(', ')}.\\n` +\n `Either add them to iconMap in @getvitops/core, or drop them from the ` +\n `\\`semantic\\` list. Available in '${uiPrefix}': ` +\n `${Object.keys(iconMap[uiMapKey!]).slice(0, 12).join(', ')}…`,\n );\n\n return include;\n}\n"],"mappings":"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"}
|