@pixelfiddler/core 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -70,13 +70,14 @@ var createResponsiveAttributes = (config, options = {}) => {
|
|
|
70
70
|
transformations = {},
|
|
71
71
|
mode = "short"
|
|
72
72
|
} = options;
|
|
73
|
+
const baseWidth = transformations.width ?? width;
|
|
73
74
|
const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);
|
|
74
75
|
const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);
|
|
75
76
|
const allBreakpoints = [.../* @__PURE__ */ new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);
|
|
76
77
|
const { candidates, descriptor } = computeCandidateWidths({
|
|
77
78
|
allBreakpoints,
|
|
78
79
|
deviceBreakpoints: sortedDeviceBreakpoints,
|
|
79
|
-
...
|
|
80
|
+
...baseWidth !== void 0 && { explicitWidth: baseWidth },
|
|
80
81
|
...sizes !== void 0 && { sizesAttr: sizes }
|
|
81
82
|
});
|
|
82
83
|
if (candidates.length === 0) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/src-set.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":";;;AAOO,IAAM,eAAA,GAAkB,IAAA;AAKxB,IAAM,0BAAA,GAA6B;AAAA,EACtC,GAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA;AACJ,CAAA;AAKO,IAAM,yBAAA,GAA4B,CAAC,EAAA,EAAI,EAAA,EAAI,IAAI,EAAA,EAAI,EAAA,EAAI,GAAA,EAAK,GAAA,EAAK,GAAG,CAAA;AA2C3E,IAAM,eAAA,GAAkB,CAAA;AAExB,SAAS,uBAAuB,MAAA,EAKoB;AAChD,EAAA,MAAM;AAAA,IACF,cAAA;AAAA,IACA,iBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACJ,GAAI,MAAA;AAGJ,EAAA,MAAM,SAAA,GAAY,CAAC,GAAG,IAAI,GAAA,CAAI,cAAc,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AACnE,EAAA,MAAM,YAAA,GAAe,CAAC,GAAG,IAAI,GAAA,CAAI,iBAAiB,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AAEzE,EAAA,IAAI,CAAC,SAAA,CAAU,MAAA,IAAU,CAAC,aAAa,MAAA,EAAQ;AAC3C,IAAA,OAAO,EAAE,UAAA,EAAY,EAAC,EAAG,YAAY,GAAA,EAAI;AAAA,EAC7C;AAEA,EAAA,MAAM,SAAA,GAAY,aAAa,CAAC,CAAA;AAChC,EAAA,MAAM,SAAA,GAAY,YAAA,CAAa,YAAA,CAAa,MAAA,GAAS,CAAC,CAAA;AAEtD,EAAA,MAAM,QAAA,GAAW,QAAQ,SAAS,CAAA;AAClC,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,GAAS,CAAA;AAIhC,EAAA,IAAI,OAAO,aAAA,KAAkB,QAAA,IAAY,CAAC,KAAA,EAAO;AAC7C,IAAA,MAAM,IAAA,GAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAErB,IAAA,MAAM,aAAa,KAAA,CAAM,IAAA;AAAA,MACrB,IAAI,GAAA;AAAA,QACA,IAAA,CACK,GAAA,CAAI,CAAA,GAAA,KAAO,OAAA,CAAQ,SAAA,EAAW,gBAAgB,GAAG,CAAC,CAAA,CAClD,GAAA,CAAI,QAAQ;AAAA;AACrB,KACJ,CAAE,MAAA,CAAO,CAAA,CAAA,KAAK,CAAA,IAAK,eAAe,CAAA;AAElC,IAAA,OAAO;AAAA,MACH,UAAA;AAAA,MACA,UAAA,EAAY;AAAA,KAChB;AAAA,EACJ;AAGA,EAAA,IAAI,KAAA,EAAO;AACP,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,GAAG,QAAQ,CAAA;AACrC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,GAAG,QAAQ,CAAA;AAErC,IAAA,MAAM,QAAQ,SAAA,GAAY,QAAA;AAC1B,IAAA,MAAM,KAAA,GAAQ,YAAY,QAAA,GAAW,eAAA;AAErC,IAAA,MAAM,aAAa,SAAA,CAAU,MAAA;AAAA,MACzB,CAAA,CAAA,KAAK,CAAA,IAAK,KAAA,IAAS,CAAA,IAAK,SAAS,KAAK;AAAA,KAC1C;AAEA,IAAA,OAAO;AAAA,MACH,UAAA;AAAA,MACA,UAAA,EAAY;AAAA,KAChB;AAAA,EACJ;AAGA,EAAA,MAAM,YAAY,SAAA,GAAY,eAAA;AAE9B,EAAA,OAAO;AAAA,IACH,YAAY,SAAA,CAAU,MAAA,CAAO,OAAK,CAAA,IAAK,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IAC1D,UAAA,EAAY;AAAA,GAChB;AACJ;AA0CO,IAAM,0BAAA,GAA6B,CACtC,MAAA,EACA,OAAA,GAAkC,EAAC,KACX;AACxB,EAAA,MAAM;AAAA,IACF,KAAA;AAAA,IACA,KAAA;AAAA,IACA,iBAAA,GAAoB,CAAC,GAAG,0BAA0B,CAAA;AAAA,IAClD,gBAAA,GAAmB,CAAC,GAAG,yBAAyB,CAAA;AAAA,IAChD,kBAAkB,EAAC;AAAA,IACnB,IAAA,GAAO;AAAA,GACX,GAAI,OAAA;AAEJ,EAAA,MAAM,uBAAA,GAA0B,CAAC,GAAG,iBAAiB,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAC3E,EAAA,MAAM,sBAAA,GAAyB,CAAC,GAAG,gBAAgB,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAEzE,EAAA,MAAM,iBAAiB,CAAC,uBAAO,GAAA,CAAI,CAAC,GAAG,sBAAA,EAAwB,GAAG,uBAAuB,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AAEjH,EAAA,MAAM,EAAE,UAAA,EAAY,UAAA,EAAW,GAAI,sBAAA,CAAuB;AAAA,IACtD,cAAA;AAAA,IACA,iBAAA,EAAmB,uBAAA;AAAA,IACnB,GAAI,KAAA,KAAU,MAAA,IAAa,EAAE,eAAe,KAAA,EAAM;AAAA,IAClD,GAAI,KAAA,KAAU,MAAA,IAAa,EAAE,WAAW,KAAA;AAAM,GACjD,CAAA;AAED,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAEzB,IAAA,OAAO,EAAE,GAAA,EAAK,MAAA,CAAO,OAAA,EAAQ;AAAA,EACjC;AAGA,EAAA,MAAM,aAAA,GAAgB,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,EAAG,KAAA,KAAW,eAAA,CAAgB,CAAA,EAAG,KAAA,EAAO,MAAA,EAAQ,eAAA,EAAiB,IAAA,EAAM,UAAU,CAAC,CAAA;AAGxH,EAAA,MAAM,YAAA,GAAe,UAAA,CAAW,UAAA,CAAW,MAAA,GAAS,CAAC,CAAA;AACrD,EAAA,MAAM,GAAA,GAAM,sBAAA;AAAA,IACR,MAAA;AAAA,IACA,EAAE,GAAG,eAAA,EAAiB,KAAA,EAAO,YAAA,EAAa;AAAA,IAC1C;AAAA,GACJ;AAEA,EAAA,MAAM,QAAA,GAAW,KAAA,KAAU,UAAA,KAAe,GAAA,GAAM,OAAA,GAAU,MAAA,CAAA;AAE1D,EAAA,OAAO;AAAA,IACH,GAAA;AAAA,IACA,GAAI,QAAA,GAAW,EAAE,KAAA,EAAO,QAAA,KAAa,EAAC;AAAA,IACtC,MAAA,EAAQ,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA;AAAA,IAC/B,GAAI,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,KAAU;AAAC,GAC3C;AACJ;AAEA,SAAS,gBAAgB,KAAA,EAAe,KAAA,EAAe,MAAA,EAA0B,eAAA,EAAwC,MAAgB,UAAA,EAA+B;AACpK,EAAA,MAAM,GAAA,GAAM,sBAAA;AAAA,IACR,MAAA;AAAA,IACA,EAAE,GAAG,eAAA,EAAiB,KAAA,EAAa;AAAA,IACnC;AAAA,GACJ;AAEA,EAAA,MAAM,IAAA,GAAO,eAAe,GAAA,GAAM,CAAA,EAAG,KAAK,CAAA,CAAA,CAAA,GAAM,CAAA,EAAG,QAAQ,CAAC,CAAA,CAAA,CAAA;AAE5D,EAAA,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AACzB;;;AClPO,IAAM,eAAe,CAAC,KAAA,KAAkB,KAAA,CAAM,OAAA,CAAQ,KAAK,EAAE,CAAA;AAG7D,IAAM,mBAAA,GAAsB,CAAC,OAAA,KAAoB;AACpD,EAAA,OAAO,OAAA,CAAQ,SAAS,GAAG,CAAA,GACrB,QAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GACnB,OAAA;AACV,CAAA;AAEO,IAAM,cAAA,GAAiB,CAI1B,GAAA,EACA,IAAA,KAEA,IAAA,CAAK,MAAA;AAAA,EACD,CAAC,GAAA,EAAK,GAAA,KAAS,OAAO,IAAA,GAAO,MAAA,GAAY,IAAI,GAAG,CAAA;AAAA,EAChD;AACJ,CAAA;AAGG,IAAM,WAAW,CAAC,CAAA,KAAc,IAAA,CAAK,GAAA,CAAI,GAAG,eAAe,CAAA;AAE3D,IAAM,OAAA,GAAU,CAAC,iBAAA,EAA4B,MAAA,KAChD,iBAAA,CAAkB,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,IAAK,MAAM,CAAA,IAAK,iBAAA,CAAkB,iBAAA,CAAkB,SAAS,CAAC,CAAA;AAEvF,IAAM,OAAA,GAAU,CAAC,KAAA,KAA6B;AACjD,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AACpB,EAAA,OAAO,CAAC,GAAG,KAAA,CAAM,QAAA,CAAS,oBAAoB,CAAC,CAAA,CAAE,GAAA;AAAA,IAC7C,CAAA,CAAA,KAAK,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI;AAAA,GACxB;AACJ,CAAA;;;AC/BO,IAAM,MAAA,GAAS;AAAA,EAClB,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,GAAA,EAAG;AAAA,EAC3C,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,GAAA,EAAG;AAAA,EAC7C,EAAC,MAAM,CAAC,KAAK,GAAG,IAAA,EAAM,KAAA,EAAO,OAAO,KAAA,EAAK;AAAA,EACzC,EAAC,MAAM,CAAC,MAAM,GAAG,IAAA,EAAM,MAAA,EAAQ,OAAO,IAAA,EAAI;AAAA,EAC1C;AAAA,IACI,IAAA,EAAM,CAAC,YAAY,CAAA;AAAA,IACnB,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,IAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EAEA,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,GAAA,EAAG;AAAA,EAC7C,EAAC,MAAM,CAAC,SAAS,GAAG,IAAA,EAAM,SAAA,EAAW,OAAO,GAAA,EAAG;AAAA,EAC/C,EAAC,MAAM,CAAC,eAAe,GAAG,IAAA,EAAM,eAAA,EAAiB,OAAO,IAAA,EAAI;AAAA,EAE5D,EAAC,MAAM,CAAC,MAAM,GAAG,IAAA,EAAM,MAAA,EAAQ,OAAO,IAAA,EAAI;AAAA,EAC1C,EAAC,MAAM,CAAC,YAAY,GAAG,IAAA,EAAM,YAAA,EAAc,OAAO,IAAA,EAAI;AAAA,EACtD,EAAC,MAAM,CAAC,UAAU,GAAG,IAAA,EAAM,UAAA,EAAY,OAAO,IAAA,EAAI;AAAA,EAClD,EAAC,MAAM,CAAC,WAAW,GAAG,IAAA,EAAM,WAAA,EAAa,OAAO,IAAA,EAAI;AAAA,EACpD,EAAC,MAAM,CAAC,YAAY,GAAG,IAAA,EAAM,YAAA,EAAc,OAAO,IAAA,EAAI;AAAA,EACtD,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,IAAA,EAAI;AAAA,EAC5C,EAAC,MAAM,CAAC,SAAS,GAAG,IAAA,EAAM,SAAA,EAAW,OAAO,IAAA,EAAI;AAAA,EAChD,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,IAAA,EAAI;AAAA,EAC5C,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,IAAA,EAAI;AAAA,EAE9C,EAAC,MAAM,CAAC,QAAA,EAAU,OAAO,CAAA,EAAG,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAO,MAAA,EAAM;AAAA,EAC/D;AAAA,IACI,IAAA,EAAM,CAAC,QAAA,EAAU,OAAO,CAAA;AAAA,IACxB,IAAA,EAAM,cAAA;AAAA,IACN,KAAA,EAAO,MAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,QAAA,EAAU,QAAQ,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,MAAA,EAAM;AAAA,EAEjE,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,YAAY,CAAA,EAAG,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,MAAA,EAAM;AAAA,EACrE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAA,EAAY,GAAG,CAAA,EAAG,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,MAAA,EAAM;AAAA,EACxE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAA,EAAY,GAAG,CAAA,EAAG,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,MAAA,EAAM;AAAA,EACxE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAU,CAAA,EAAG,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAI;AAAA,EAC/D,EAAC,MAAM,CAAC,MAAA,EAAQ,OAAO,CAAA,EAAG,IAAA,EAAM,YAAA,EAAc,KAAA,EAAO,MAAA,EAAM;AAAA,EAC3D,EAAC,MAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA,EAAG,IAAA,EAAM,aAAA,EAAe,KAAA,EAAO,MAAA,EAAM;AAAA,EAC7D,EAAC,MAAM,CAAC,MAAA,EAAQ,aAAa,CAAA,EAAG,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,OAAA,EAAO;AAAA,EAExE,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAI;AAAA,EAClD;AAAA,IACI,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAO,CAAA;AAAA,IACtB,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,MAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,EAAG,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAO,MAAA,EAAM;AAAA,EAC/D,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,UAAU,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,OAAA,EAAO;AAAA,EAClE,EAAC,MAAM,CAAC,MAAA,EAAQ,UAAU,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,MAAA,EAAM;AAAA,EACjE;AAAA,IACI,IAAA,EAAM,CAAC,MAAA,EAAQ,YAAY,CAAA;AAAA,IAC3B,IAAA,EAAM,iBAAA;AAAA,IACN,KAAA,EAAO,OAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,MAAA,EAAQ,mBAAmB,CAAA,EAAG,IAAA,EAAM,wBAAA,EAA0B,KAAA,EAAO,SAAA,EAAS;AAAA,EAEtF,EAAC,MAAM,CAAC,WAAA,EAAa,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,IAAA,EAAI;AAAA,EAC5D,EAAC,MAAM,CAAC,WAAA,EAAa,SAAS,CAAA,EAAG,IAAA,EAAM,mBAAA,EAAqB,KAAA,EAAO,MAAA,EAAM;AAAA,EACzE,EAAC,MAAM,CAAC,WAAA,EAAa,MAAM,CAAA,EAAG,IAAA,EAAM,gBAAA,EAAkB,KAAA,EAAO,MAAA,EAAM;AAAA,EACnE,EAAC,MAAM,CAAC,WAAA,EAAa,OAAO,CAAA,EAAG,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,MAAA,EAAM;AAAA,EACrE,EAAC,MAAM,CAAC,WAAA,EAAa,QAAQ,CAAA,EAAG,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,MAAA,EAAM;AAAA,EACvE,EAAC,MAAM,CAAC,WAAA,EAAa,UAAU,CAAA,EAAG,IAAA,EAAM,oBAAA,EAAsB,KAAA,EAAO,MAAA;AACzE,CAAA;;;ACrCO,IAAM,8BAAA,GAAiC,CAC1C,OAAA,EACA,IAAA,GAAiB,OAAA,KACR;AACT,EAAA,MAAM,SAAkC,EAAC;AAEzC,EAAA,KAAA,MAAW,QAAQ,MAAA,EAAQ;AACvB,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,OAAA,EAAS,IAAA,CAAK,IAAI,CAAA;AAC/C,IAAA,IAAI,SAAS,IAAA,EAAM;AAEnB,IAAA,MAAM,OACF,IAAA,KAAS,OAAA,IAAW,KAAK,KAAA,GAAQ,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA;AAEvD,IAAA,IAAI,UAAA,GAAa,KAAA;AACjB,IAAA,IAAI,eAAe,IAAA,EAAM;AACrB,MAAA,UAAA,GAAa,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,IACrC;AAEA,IAAA,MAAA,CAAO,KAAK,CAAC,IAAA,EAAM,MAAA,CAAO,UAAU,CAAC,CAAC,CAAA;AAAA,EAC1C;AAGA,EAAA,OAAO,IAAI,eAAA;AAAA,IACP,MAAA,CAAO,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAC,CAAA,EAAG,CAAC,CAAC;AAAA,IAC/B,QAAA,EAAS;AAEf;AA2CA,IAAM,sBAAA,GAAyB,CAAC,GAAA,KAAwB;AACpD,EAAA,MAAM,UAAA,GAAa,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAClC,EAAA,OAAO,eAAe,EAAA,GAAK,GAAA,GAAM,GAAA,CAAI,KAAA,CAAM,GAAG,UAAU,CAAA;AAC5D,CAAA;AAEO,IAAM,sBAAA,GAAyB,CAClC,MAAA,EACA,OAAA,EACA,OAAiB,OAAA,KAChB;AAED,EAAA,MAAM,OAAA,GAAU,mBAAA,CAAoB,sBAAA,CAAuB,MAAA,CAAO,OAAO,CAAC,CAAA;AAE1E,EAAA,IAAI,QAAQ,QAAA,EAAU;AAClB,IAAA,OAAO,GAAG,OAAO,CAAA,SAAA,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,KAAA,GAAQ,8BAAA,CAA+B,OAAA,EAAS,IAAI,CAAA;AAE1D,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAC9B","file":"index.cjs","sourcesContent":["import { buildTransformationUrl, NameMode } from './url-builder';\r\nimport { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { clampMax, nearest, parseVW } from './utils';\r\n\r\n/**\r\n * Maximum supported image width\r\n */\r\nexport const MAX_IMAGE_WIDTH = 4096;\r\n\r\n/**\r\n * Default device breakpoints for responsive srcset generation\r\n */\r\nexport const DEFAULT_DEVICE_BREAKPOINTS = [\r\n 320,\r\n 375,\r\n 640,\r\n 768,\r\n 1024,\r\n 1280,\r\n 1536,\r\n 1920\r\n] as const;\r\n\r\n/**\r\n * Default image breakpoints for smaller images (icons, thumbnails)\r\n */\r\nexport const DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384] as const;\r\n\r\n/**\r\n * Options for responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageOptions {\r\n /**\r\n * The `sizes` attribute value (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * When provided, generates width descriptors (`w`) for responsive layouts.\r\n */\r\n sizes?: string;\r\n /**\r\n * Fixed display width in CSS pixels.\r\n * When provided without `sizes`, generates DPR descriptors (`x`).\r\n */\r\n width?: number;\r\n /** Device breakpoints for viewport-based sizing (default: DEFAULT_DEVICE_BREAKPOINTS) */\r\n deviceBreakpoints?: number[];\r\n /** Image breakpoints for smaller images (default: DEFAULT_IMAGE_BREAKPOINTS) */\r\n imageBreakpoints?: number[];\r\n /** Base transformation options to apply to all variants */\r\n transformations?: TransformationOptions;\r\n /** Whether to use short or long parameter names (default: 'short') */\r\n mode?: NameMode;\r\n}\r\n\r\n/**\r\n * Result of responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageResult {\r\n /** The src attribute value (largest/default variant) */\r\n src: string;\r\n /** The srcset attribute value */\r\n srcSet?: string;\r\n /** The sizes attribute value (for width descriptors) */\r\n sizes?: string;\r\n /** The width attribute value (when explicitly provided) */\r\n width?: number;\r\n}\r\n\r\n/**\r\n * Computes candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction computeCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr\r\n } = params;\r\n\r\n // ---- Normalize & guard ----\r\n const sortedAll = [...new Set(allBreakpoints)].sort((a, b) => a - b);\r\n const sortedDevice = [...new Set(deviceBreakpoints)].sort((a, b) => a - b);\r\n\r\n if (!sortedAll.length || !sortedDevice.length) {\r\n return { candidates: [], descriptor: 'w' };\r\n }\r\n\r\n const minDevice = sortedDevice[0]!;\r\n const maxDevice = sortedDevice[sortedDevice.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n // Explicit width (fixed layout) → x descriptors ----\r\n // Prefer this when layout width is known and sizes does NOT imply vw scaling\r\n if (typeof explicitWidth === 'number' && !hasVW) {\r\n const DPRs = [1, 2, 3];\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(sortedAll, explicitWidth * dpr))\r\n .map(clampMax)\r\n )\r\n ).filter(w => w <= MAX_IMAGE_WIDTH);\r\n\r\n return {\r\n candidates,\r\n descriptor: 'x'\r\n };\r\n }\r\n\r\n // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const minRatio = Math.min(...vwRatios);\r\n const maxRatio = Math.max(...vwRatios);\r\n\r\n const minPx = minDevice * minRatio;\r\n const maxPx = maxDevice * maxRatio * DEFAULT_MAX_DPR;\r\n\r\n const candidates = sortedAll.filter(\r\n w => w >= minPx && w <= clampMax(maxPx)\r\n );\r\n\r\n return {\r\n candidates,\r\n descriptor: 'w'\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const maxUseful = maxDevice * DEFAULT_MAX_DPR;\r\n\r\n return {\r\n candidates: sortedAll.filter(w => w <= clampMax(maxUseful)),\r\n descriptor: 'w'\r\n };\r\n}\r\n\r\n/**\r\n * Generates responsive image attributes (src, srcSet, sizes) for optimal loading.\r\n *\r\n * Supports two strategies:\r\n * 1. **Responsive (with `sizes`)**: Uses width descriptors (`w`) for fluid layouts\r\n * where image size varies with viewport.\r\n * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size\r\n * images that need high-DPI support.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - Options for responsive image generation\r\n * @returns Object containing src, srcSet, and optionally sizes attributes\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/photo.jpg' };\r\n *\r\n * // Responsive image with sizes attribute (uses `w` descriptors)\r\n * createResponsiveAttributes(config, { sizes: '(max-width: 768px) 100vw, 50vw' });\r\n * // => {\r\n * // src: '...?w=3840',\r\n * // srcSet: '...?w=640 640w, ...?w=750 750w, ..., ...?w=3840 3840w',\r\n * // sizes: '(max-width: 768px) 100vw, 50vw'\r\n * // }\r\n *\r\n * // Fixed-width image (uses `x` descriptors)\r\n * createResponsiveAttributes(config, { width: 400 });\r\n * // => {\r\n * // src: '...?w=384',\r\n * // srcSet: '...?w=384 1x, ...?w=828 2x',\r\n * // width: 400\r\n * // }\r\n *\r\n * // With transformations\r\n * createResponsiveAttributes(config, {\r\n * sizes: '100vw',\r\n * transformations: { format: 'WEBP', quality: 80 }\r\n * });\r\n * ```\r\n */\r\nexport const createResponsiveAttributes = (\r\n config: UrlBuilderConfig,\r\n options: ResponsiveImageOptions = {}\r\n): ResponsiveImageResult => {\r\n const {\r\n sizes,\r\n width,\r\n deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],\r\n imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],\r\n transformations = {},\r\n mode = 'short',\r\n } = options;\r\n\r\n const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);\r\n const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);\r\n\r\n const allBreakpoints = [...new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);\r\n\r\n const { candidates, descriptor } = computeCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(width !== undefined && { explicitWidth: width }),\r\n ...(sizes !== undefined && { sizesAttr: sizes }),\r\n });\r\n\r\n if (candidates.length === 0) {\r\n // Fallback: no valid candidates, return base URL\r\n return { src: config.baseUrl };\r\n }\r\n\r\n // Build srcSet entries\r\n const srcSetEntries = candidates.map((w, index,) => buildSrcEntries(w, index, config, transformations, mode, descriptor));\r\n\r\n // Default src is the largest candidate\r\n const largestWidth = candidates[candidates.length - 1]!;\r\n const src = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: largestWidth },\r\n mode\r\n );\r\n\r\n const endSizes = sizes ?? (descriptor === 'w' ? '100vw' : undefined);\r\n\r\n return {\r\n src,\r\n ...(endSizes ? { sizes: endSizes } : {}),\r\n srcSet: srcSetEntries.join(', '),\r\n ...(width !== undefined ? { width } : {}),\r\n };\r\n};\r\n\r\nfunction buildSrcEntries(width: number, index: number, config: UrlBuilderConfig, transformations: TransformationOptions, mode: NameMode, descriptor: 'w' | 'x'): string {\r\n const url = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: width },\r\n mode\r\n );\r\n\r\n const desc = descriptor === 'w' ? `${width}w` : `${index + 1}x`;\r\n\r\n return `${url} ${desc}`;\r\n}\r\n","import { Path, PathValue } from './util-types';\r\nimport { MAX_IMAGE_WIDTH } from './src-set';\r\n\r\nexport const normalizeHex = (value: string) => value.replace('#', '')\r\n\r\n\r\nexport const removeTrailingSlash = (baseUrl: string) => {\r\n return baseUrl.endsWith('/')\r\n ? baseUrl.slice(0, -1)\r\n : baseUrl;\r\n}\r\n\r\nexport const getNestedValue = <\r\n T,\r\n P extends Path<T>\r\n>(\r\n obj: T,\r\n path: P\r\n): PathValue<T, P> | undefined =>\r\n path.reduce<any>(\r\n (acc, key) => (acc == null ? undefined : acc[key]),\r\n obj\r\n );\r\n\r\n\r\nexport const clampMax = (v: number) => Math.min(v, MAX_IMAGE_WIDTH);\r\n\r\nexport const nearest = (sortedBreakpoints: number[],target: number) =>\r\n sortedBreakpoints.find(w => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1]!;\r\n\r\nexport const parseVW = (sizes?: string): number[] => {\r\n if (!sizes) return [];\r\n return [...sizes.matchAll(/(\\d+(?:\\.\\d+)?)vw/g)].map(\r\n m => Number(m[1]) / 100\r\n );\r\n};\r\n\r\n","import { ParamSpec, Path } from './util-types';\r\nimport { TransformationOptions } from './types';\r\nimport { normalizeHex } from './utils';\r\n\r\nexport const PARAMS = [\r\n {path: ['width'], long: 'width', short: 'w'},\r\n {path: ['height'], long: 'height', short: 'h'},\r\n {path: ['dpr'], long: 'dpr', short: 'dpr'},\r\n {path: ['mode'], long: 'mode', short: 'rm'},\r\n {\r\n path: ['background'],\r\n long: 'background',\r\n short: 'bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n\r\n {path: ['format'], long: 'format', short: 'f'},\r\n {path: ['quality'], long: 'quality', short: 'q'},\r\n {path: ['stripMetadata'], long: 'stripMetadata', short: 'st'},\r\n\r\n {path: ['blur'], long: 'blur', short: 'bl'},\r\n {path: ['brightness'], long: 'brightness', short: 'br'},\r\n {path: ['contrast'], long: 'contrast', short: 'ct'},\r\n {path: ['grayscale'], long: 'grayscale', short: 'gs'},\r\n {path: ['saturation'], long: 'saturation', short: 'sa'},\r\n {path: ['sepia'], long: 'sepia', short: 'sp'},\r\n {path: ['sharpen'], long: 'sharpen', short: 'sh'},\r\n {path: ['noise'], long: 'noise', short: 'ns'},\r\n {path: ['rotate'], long: 'rotate', short: 'rt'},\r\n\r\n {path: ['border', 'width'], long: 'border.width', short: 'bo.w'},\r\n {\r\n path: ['border', 'color'],\r\n long: 'border.color',\r\n short: 'bo.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['border', 'radius'], long: 'border.radius', short: 'bo.r'},\r\n\r\n {path: ['crop', 'type'], long: 'crop.type', short: 'cr.t'},\r\n {path: ['crop', 'objectType'], long: 'crop.objectType', short: 'cr.o'},\r\n {path: ['crop', 'focus', 'position', 'x'], long: 'crop.x', short: 'cr.x'},\r\n {path: ['crop', 'focus', 'position', 'y'], long: 'crop.y', short: 'cr.y'},\r\n {path: ['crop', 'focus', 'strategy'], long: 'crop', short: 'cr'},\r\n {path: ['crop', 'width'], long: 'crop.width', short: 'cr.w'},\r\n {path: ['crop', 'height'], long: 'crop.height', short: 'cr.h'},\r\n {path: ['crop', 'afterResize'], long: 'crop.afterResize', short: 'cr.ar'},\r\n\r\n {path: ['text', 'text'], long: 'text', short: 'tx'},\r\n {\r\n path: ['text', 'color'],\r\n long: 'text.color',\r\n short: 'tx.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'opacity'], long: 'text.opacity', short: 'tx.o'},\r\n {path: ['text', 'size'], long: 'text.size', short: 'tx.s'},\r\n {path: ['text', 'font'], long: 'text.font', short: 'tx.f'},\r\n {path: ['text', 'fontSize'], long: 'text.fontSize', short: 'tx.fs'},\r\n {path: ['text', 'position'], long: 'text.position', short: 'tx.p'},\r\n {\r\n path: ['text', 'background'],\r\n long: 'text.background',\r\n short: 'tx.bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'backgroundOpacity'], long: 'text.backgroundOpacity', short: 'tx.bg.o'},\r\n\r\n {path: ['watermark', 'name'], long: 'watermark', short: 'wm'},\r\n {path: ['watermark', 'opacity'], long: 'watermark.opacity', short: 'wm.o'},\r\n {path: ['watermark', 'size'], long: 'watermark.size', short: 'wm.s'},\r\n {path: ['watermark', 'width'], long: 'watermark.width', short: 'wm.w'},\r\n {path: ['watermark', 'height'], long: 'watermark.height', short: 'wm.h'},\r\n {path: ['watermark', 'position'], long: 'watermark.position', short: 'wm.p'},\r\n] as const satisfies readonly ParamSpec<\r\n TransformationOptions,\r\n Path<TransformationOptions>\r\n>[];\r\n","import { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { getNestedValue, removeTrailingSlash } from './utils';\r\nimport { PARAMS } from './config';\r\n\r\n/**\r\n * Determines which parameter names to use in the query string.\r\n * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)\r\n * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)\r\n */\r\nexport type NameMode = 'short' | 'long';\r\n\r\n/**\r\n * Converts transformation options into a URL-encoded query string.\r\n *\r\n * Iterates through all defined parameters in the PARAMS config, extracts values\r\n * from the options object using their paths, applies any normalization functions\r\n * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.\r\n *\r\n * @param options - The transformation options object\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns URL-encoded query string (without leading `?`)\r\n *\r\n * @example\r\n * ```ts\r\n * // Using short aliases (default)\r\n * buildQueryParams({ width: 800, height: 600, quality: 80 });\r\n * // => 'w=800&h=600&q=80'\r\n *\r\n * // Using long parameter names\r\n * buildQueryParams({ width: 800, format: 'webp' }, 'long');\r\n * // => 'width=800&format=webp'\r\n *\r\n * // Nested options\r\n * buildQueryParams({ border: { width: 2, color: '#ff0000' } });\r\n * // => 'bo.w=2&bo.c=ff0000'\r\n * ```\r\n */\r\nexport const buildTransformationQueryParams = (\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n): string => {\r\n const params: Array<[string, string]> = [];\r\n\r\n for (const spec of PARAMS) {\r\n const value = getNestedValue(options, spec.path);\r\n if (value == null) continue;\r\n\r\n const name =\r\n mode === 'short' && spec.short ? spec.short : spec.long;\r\n\r\n let normalized = value\r\n if ('normalize' in spec) {\r\n normalized = spec.normalize(value)\r\n }\r\n\r\n params.push([name, String(normalized)]);\r\n }\r\n\r\n\r\n return new URLSearchParams(\r\n params.map(([k, v]) => [k, v])\r\n ).toString();\r\n\r\n};\r\n\r\n/**\r\n * Builds a complete transformation URL from a base URL and transformation options.\r\n *\r\n * Combines the configured base URL with query parameters generated from the\r\n * transformation options. Handles the special `original` flag which returns\r\n * the unmodified source image.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - The transformation options to apply\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns The complete URL string with query parameters\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://example.com/images/photo.jpg?w=400&h=300'\r\n *\r\n * // Multiple transformations\r\n * buildTransformationUrl(config, {\r\n * width: 800,\r\n * format: 'webp',\r\n * quality: 85,\r\n * blur: 5\r\n * });\r\n * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'\r\n *\r\n * // Request original image (no transformations)\r\n * buildTransformationUrl(config, { original: true });\r\n * // => 'https://example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://example.com/images/photo.jpg?width=400'\r\n * ```\r\n */\r\n/**\r\n * Extracts the base URL path without query parameters\r\n */\r\nconst getBaseUrlWithoutQuery = (url: string): string => {\r\n const queryIndex = url.indexOf('?');\r\n return queryIndex === -1 ? url : url.slice(0, queryIndex);\r\n};\r\n\r\nexport const buildTransformationUrl = (\r\n config: UrlBuilderConfig,\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n) => {\r\n // Strip any existing query params from baseUrl - transformations replace them\r\n const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));\r\n\r\n if (options.original) {\r\n return `${baseUrl}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(options, mode);\r\n\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/src-set.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import { buildTransformationUrl, NameMode } from './url-builder';\r\nimport { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { clampMax, nearest, parseVW } from './utils';\r\n\r\n/**\r\n * Maximum supported image width\r\n */\r\nexport const MAX_IMAGE_WIDTH = 4096;\r\n\r\n/**\r\n * Default device breakpoints for responsive srcset generation\r\n */\r\nexport const DEFAULT_DEVICE_BREAKPOINTS = [\r\n 320,\r\n 375,\r\n 640,\r\n 768,\r\n 1024,\r\n 1280,\r\n 1536,\r\n 1920\r\n] as const;\r\n\r\n/**\r\n * Default image breakpoints for smaller images (icons, thumbnails)\r\n */\r\nexport const DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384] as const;\r\n\r\n/**\r\n * Options for responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageOptions {\r\n /**\r\n * The `sizes` attribute value (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * When provided, generates width descriptors (`w`) for responsive layouts.\r\n */\r\n sizes?: string;\r\n /**\r\n * Fixed display width in CSS pixels.\r\n * When provided without `sizes`, generates DPR descriptors (`x`).\r\n */\r\n width?: number;\r\n /** Device breakpoints for viewport-based sizing (default: DEFAULT_DEVICE_BREAKPOINTS) */\r\n deviceBreakpoints?: number[];\r\n /** Image breakpoints for smaller images (default: DEFAULT_IMAGE_BREAKPOINTS) */\r\n imageBreakpoints?: number[];\r\n /** Base transformation options to apply to all variants */\r\n transformations?: TransformationOptions;\r\n /** Whether to use short or long parameter names (default: 'short') */\r\n mode?: NameMode;\r\n}\r\n\r\n/**\r\n * Result of responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageResult {\r\n /** The src attribute value (largest/default variant) */\r\n src: string;\r\n /** The srcset attribute value */\r\n srcSet?: string;\r\n /** The sizes attribute value (for width descriptors) */\r\n sizes?: string;\r\n /** The width attribute value (when explicitly provided) */\r\n width?: number;\r\n}\r\n\r\n/**\r\n * Computes candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction computeCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr\r\n } = params;\r\n\r\n // ---- Normalize & guard ----\r\n const sortedAll = [...new Set(allBreakpoints)].sort((a, b) => a - b);\r\n const sortedDevice = [...new Set(deviceBreakpoints)].sort((a, b) => a - b);\r\n\r\n if (!sortedAll.length || !sortedDevice.length) {\r\n return { candidates: [], descriptor: 'w' };\r\n }\r\n\r\n const minDevice = sortedDevice[0]!;\r\n const maxDevice = sortedDevice[sortedDevice.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n // Explicit width (fixed layout) → x descriptors ----\r\n // Prefer this when layout width is known and sizes does NOT imply vw scaling\r\n if (typeof explicitWidth === 'number' && !hasVW) {\r\n const DPRs = [1, 2, 3];\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(sortedAll, explicitWidth * dpr))\r\n .map(clampMax)\r\n )\r\n ).filter(w => w <= MAX_IMAGE_WIDTH);\r\n\r\n return {\r\n candidates,\r\n descriptor: 'x'\r\n };\r\n }\r\n\r\n // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const minRatio = Math.min(...vwRatios);\r\n const maxRatio = Math.max(...vwRatios);\r\n\r\n const minPx = minDevice * minRatio;\r\n const maxPx = maxDevice * maxRatio * DEFAULT_MAX_DPR;\r\n\r\n const candidates = sortedAll.filter(\r\n w => w >= minPx && w <= clampMax(maxPx)\r\n );\r\n\r\n return {\r\n candidates,\r\n descriptor: 'w'\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const maxUseful = maxDevice * DEFAULT_MAX_DPR;\r\n\r\n return {\r\n candidates: sortedAll.filter(w => w <= clampMax(maxUseful)),\r\n descriptor: 'w'\r\n };\r\n}\r\n\r\n/**\r\n * Generates responsive image attributes (src, srcSet, sizes) for optimal loading.\r\n *\r\n * Supports two strategies:\r\n * 1. **Responsive (with `sizes`)**: Uses width descriptors (`w`) for fluid layouts\r\n * where image size varies with viewport.\r\n * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size\r\n * images that need high-DPI support.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - Options for responsive image generation\r\n * @returns Object containing src, srcSet, and optionally sizes attributes\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/photo.jpg' };\r\n *\r\n * // Responsive image with sizes attribute (uses `w` descriptors)\r\n * createResponsiveAttributes(config, { sizes: '(max-width: 768px) 100vw, 50vw' });\r\n * // => {\r\n * // src: '...?w=3840',\r\n * // srcSet: '...?w=640 640w, ...?w=750 750w, ..., ...?w=3840 3840w',\r\n * // sizes: '(max-width: 768px) 100vw, 50vw'\r\n * // }\r\n *\r\n * // Fixed-width image (uses `x` descriptors)\r\n * createResponsiveAttributes(config, { width: 400 });\r\n * // => {\r\n * // src: '...?w=384',\r\n * // srcSet: '...?w=384 1x, ...?w=828 2x',\r\n * // width: 400\r\n * // }\r\n *\r\n * // With transformations\r\n * createResponsiveAttributes(config, {\r\n * sizes: '100vw',\r\n * transformations: { format: 'WEBP', quality: 80 }\r\n * });\r\n * ```\r\n */\r\nexport const createResponsiveAttributes = (\r\n config: UrlBuilderConfig,\r\n options: ResponsiveImageOptions = {}\r\n): ResponsiveImageResult => {\r\n const {\r\n sizes,\r\n width,\r\n deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],\r\n imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],\r\n transformations = {},\r\n mode = 'short',\r\n } = options;\r\n\r\n // If transformations.width is set, it takes precedence as the base width\r\n const baseWidth = transformations.width ?? width;\r\n\r\n const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);\r\n const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);\r\n\r\n const allBreakpoints = [...new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);\r\n\r\n const { candidates, descriptor } = computeCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(baseWidth !== undefined && { explicitWidth: baseWidth }),\r\n ...(sizes !== undefined && { sizesAttr: sizes }),\r\n });\r\n\r\n if (candidates.length === 0) {\r\n // Fallback: no valid candidates, return base URL\r\n return { src: config.baseUrl };\r\n }\r\n\r\n // Build srcSet entries\r\n const srcSetEntries = candidates.map((w, index,) => buildSrcEntries(w, index, config, transformations, mode, descriptor));\r\n\r\n // Default src is the largest candidate\r\n const largestWidth = candidates[candidates.length - 1]!;\r\n const src = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: largestWidth },\r\n mode\r\n );\r\n\r\n const endSizes = sizes ?? (descriptor === 'w' ? '100vw' : undefined);\r\n\r\n return {\r\n src,\r\n ...(endSizes ? { sizes: endSizes } : {}),\r\n srcSet: srcSetEntries.join(', '),\r\n ...(width !== undefined ? { width } : {}),\r\n };\r\n};\r\n\r\nfunction buildSrcEntries(width: number, index: number, config: UrlBuilderConfig, transformations: TransformationOptions, mode: NameMode, descriptor: 'w' | 'x'): string {\r\n const url = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: width },\r\n mode\r\n );\r\n\r\n const desc = descriptor === 'w' ? `${width}w` : `${index + 1}x`;\r\n\r\n return `${url} ${desc}`;\r\n}\r\n","import { Path, PathValue } from './util-types';\r\nimport { MAX_IMAGE_WIDTH } from './src-set';\r\n\r\nexport const normalizeHex = (value: string) => value.replace('#', '')\r\n\r\n\r\nexport const removeTrailingSlash = (baseUrl: string) => {\r\n return baseUrl.endsWith('/')\r\n ? baseUrl.slice(0, -1)\r\n : baseUrl;\r\n}\r\n\r\nexport const getNestedValue = <\r\n T,\r\n P extends Path<T>\r\n>(\r\n obj: T,\r\n path: P\r\n): PathValue<T, P> | undefined =>\r\n path.reduce<any>(\r\n (acc, key) => (acc == null ? undefined : acc[key]),\r\n obj\r\n );\r\n\r\n\r\nexport const clampMax = (v: number) => Math.min(v, MAX_IMAGE_WIDTH);\r\n\r\nexport const nearest = (sortedBreakpoints: number[],target: number) =>\r\n sortedBreakpoints.find(w => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1]!;\r\n\r\nexport const parseVW = (sizes?: string): number[] => {\r\n if (!sizes) return [];\r\n return [...sizes.matchAll(/(\\d+(?:\\.\\d+)?)vw/g)].map(\r\n m => Number(m[1]) / 100\r\n );\r\n};\r\n\r\n","import { ParamSpec, Path } from './util-types';\r\nimport { TransformationOptions } from './types';\r\nimport { normalizeHex } from './utils';\r\n\r\nexport const PARAMS = [\r\n {path: ['width'], long: 'width', short: 'w'},\r\n {path: ['height'], long: 'height', short: 'h'},\r\n {path: ['dpr'], long: 'dpr', short: 'dpr'},\r\n {path: ['mode'], long: 'mode', short: 'rm'},\r\n {\r\n path: ['background'],\r\n long: 'background',\r\n short: 'bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n\r\n {path: ['format'], long: 'format', short: 'f'},\r\n {path: ['quality'], long: 'quality', short: 'q'},\r\n {path: ['stripMetadata'], long: 'stripMetadata', short: 'st'},\r\n\r\n {path: ['blur'], long: 'blur', short: 'bl'},\r\n {path: ['brightness'], long: 'brightness', short: 'br'},\r\n {path: ['contrast'], long: 'contrast', short: 'ct'},\r\n {path: ['grayscale'], long: 'grayscale', short: 'gs'},\r\n {path: ['saturation'], long: 'saturation', short: 'sa'},\r\n {path: ['sepia'], long: 'sepia', short: 'sp'},\r\n {path: ['sharpen'], long: 'sharpen', short: 'sh'},\r\n {path: ['noise'], long: 'noise', short: 'ns'},\r\n {path: ['rotate'], long: 'rotate', short: 'rt'},\r\n\r\n {path: ['border', 'width'], long: 'border.width', short: 'bo.w'},\r\n {\r\n path: ['border', 'color'],\r\n long: 'border.color',\r\n short: 'bo.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['border', 'radius'], long: 'border.radius', short: 'bo.r'},\r\n\r\n {path: ['crop', 'type'], long: 'crop.type', short: 'cr.t'},\r\n {path: ['crop', 'objectType'], long: 'crop.objectType', short: 'cr.o'},\r\n {path: ['crop', 'focus', 'position', 'x'], long: 'crop.x', short: 'cr.x'},\r\n {path: ['crop', 'focus', 'position', 'y'], long: 'crop.y', short: 'cr.y'},\r\n {path: ['crop', 'focus', 'strategy'], long: 'crop', short: 'cr'},\r\n {path: ['crop', 'width'], long: 'crop.width', short: 'cr.w'},\r\n {path: ['crop', 'height'], long: 'crop.height', short: 'cr.h'},\r\n {path: ['crop', 'afterResize'], long: 'crop.afterResize', short: 'cr.ar'},\r\n\r\n {path: ['text', 'text'], long: 'text', short: 'tx'},\r\n {\r\n path: ['text', 'color'],\r\n long: 'text.color',\r\n short: 'tx.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'opacity'], long: 'text.opacity', short: 'tx.o'},\r\n {path: ['text', 'size'], long: 'text.size', short: 'tx.s'},\r\n {path: ['text', 'font'], long: 'text.font', short: 'tx.f'},\r\n {path: ['text', 'fontSize'], long: 'text.fontSize', short: 'tx.fs'},\r\n {path: ['text', 'position'], long: 'text.position', short: 'tx.p'},\r\n {\r\n path: ['text', 'background'],\r\n long: 'text.background',\r\n short: 'tx.bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'backgroundOpacity'], long: 'text.backgroundOpacity', short: 'tx.bg.o'},\r\n\r\n {path: ['watermark', 'name'], long: 'watermark', short: 'wm'},\r\n {path: ['watermark', 'opacity'], long: 'watermark.opacity', short: 'wm.o'},\r\n {path: ['watermark', 'size'], long: 'watermark.size', short: 'wm.s'},\r\n {path: ['watermark', 'width'], long: 'watermark.width', short: 'wm.w'},\r\n {path: ['watermark', 'height'], long: 'watermark.height', short: 'wm.h'},\r\n {path: ['watermark', 'position'], long: 'watermark.position', short: 'wm.p'},\r\n] as const satisfies readonly ParamSpec<\r\n TransformationOptions,\r\n Path<TransformationOptions>\r\n>[];\r\n","import { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { getNestedValue, removeTrailingSlash } from './utils';\r\nimport { PARAMS } from './config';\r\n\r\n/**\r\n * Determines which parameter names to use in the query string.\r\n * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)\r\n * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)\r\n */\r\nexport type NameMode = 'short' | 'long';\r\n\r\n/**\r\n * Converts transformation options into a URL-encoded query string.\r\n *\r\n * Iterates through all defined parameters in the PARAMS config, extracts values\r\n * from the options object using their paths, applies any normalization functions\r\n * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.\r\n *\r\n * @param options - The transformation options object\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns URL-encoded query string (without leading `?`)\r\n *\r\n * @example\r\n * ```ts\r\n * // Using short aliases (default)\r\n * buildQueryParams({ width: 800, height: 600, quality: 80 });\r\n * // => 'w=800&h=600&q=80'\r\n *\r\n * // Using long parameter names\r\n * buildQueryParams({ width: 800, format: 'webp' }, 'long');\r\n * // => 'width=800&format=webp'\r\n *\r\n * // Nested options\r\n * buildQueryParams({ border: { width: 2, color: '#ff0000' } });\r\n * // => 'bo.w=2&bo.c=ff0000'\r\n * ```\r\n */\r\nexport const buildTransformationQueryParams = (\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n): string => {\r\n const params: Array<[string, string]> = [];\r\n\r\n for (const spec of PARAMS) {\r\n const value = getNestedValue(options, spec.path);\r\n if (value == null) continue;\r\n\r\n const name =\r\n mode === 'short' && spec.short ? spec.short : spec.long;\r\n\r\n let normalized = value\r\n if ('normalize' in spec) {\r\n normalized = spec.normalize(value)\r\n }\r\n\r\n params.push([name, String(normalized)]);\r\n }\r\n\r\n\r\n return new URLSearchParams(\r\n params.map(([k, v]) => [k, v])\r\n ).toString();\r\n\r\n};\r\n\r\n/**\r\n * Builds a complete transformation URL from a base URL and transformation options.\r\n *\r\n * Combines the configured base URL with query parameters generated from the\r\n * transformation options. Handles the special `original` flag which returns\r\n * the unmodified source image.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - The transformation options to apply\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns The complete URL string with query parameters\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://example.com/images/photo.jpg?w=400&h=300'\r\n *\r\n * // Multiple transformations\r\n * buildTransformationUrl(config, {\r\n * width: 800,\r\n * format: 'webp',\r\n * quality: 85,\r\n * blur: 5\r\n * });\r\n * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'\r\n *\r\n * // Request original image (no transformations)\r\n * buildTransformationUrl(config, { original: true });\r\n * // => 'https://example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://example.com/images/photo.jpg?width=400'\r\n * ```\r\n */\r\n/**\r\n * Extracts the base URL path without query parameters\r\n */\r\nconst getBaseUrlWithoutQuery = (url: string): string => {\r\n const queryIndex = url.indexOf('?');\r\n return queryIndex === -1 ? url : url.slice(0, queryIndex);\r\n};\r\n\r\nexport const buildTransformationUrl = (\r\n config: UrlBuilderConfig,\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n) => {\r\n // Strip any existing query params from baseUrl - transformations replace them\r\n const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));\r\n\r\n if (options.original) {\r\n return `${baseUrl}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(options, mode);\r\n\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
|
package/dist/index.js
CHANGED
|
@@ -68,13 +68,14 @@ var createResponsiveAttributes = (config, options = {}) => {
|
|
|
68
68
|
transformations = {},
|
|
69
69
|
mode = "short"
|
|
70
70
|
} = options;
|
|
71
|
+
const baseWidth = transformations.width ?? width;
|
|
71
72
|
const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);
|
|
72
73
|
const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);
|
|
73
74
|
const allBreakpoints = [.../* @__PURE__ */ new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);
|
|
74
75
|
const { candidates, descriptor } = computeCandidateWidths({
|
|
75
76
|
allBreakpoints,
|
|
76
77
|
deviceBreakpoints: sortedDeviceBreakpoints,
|
|
77
|
-
...
|
|
78
|
+
...baseWidth !== void 0 && { explicitWidth: baseWidth },
|
|
78
79
|
...sizes !== void 0 && { sizesAttr: sizes }
|
|
79
80
|
});
|
|
80
81
|
if (candidates.length === 0) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/src-set.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { buildTransformationUrl, NameMode } from './url-builder';\r\nimport { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { clampMax, nearest, parseVW } from './utils';\r\n\r\n/**\r\n * Maximum supported image width\r\n */\r\nexport const MAX_IMAGE_WIDTH = 4096;\r\n\r\n/**\r\n * Default device breakpoints for responsive srcset generation\r\n */\r\nexport const DEFAULT_DEVICE_BREAKPOINTS = [\r\n 320,\r\n 375,\r\n 640,\r\n 768,\r\n 1024,\r\n 1280,\r\n 1536,\r\n 1920\r\n] as const;\r\n\r\n/**\r\n * Default image breakpoints for smaller images (icons, thumbnails)\r\n */\r\nexport const DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384] as const;\r\n\r\n/**\r\n * Options for responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageOptions {\r\n /**\r\n * The `sizes` attribute value (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * When provided, generates width descriptors (`w`) for responsive layouts.\r\n */\r\n sizes?: string;\r\n /**\r\n * Fixed display width in CSS pixels.\r\n * When provided without `sizes`, generates DPR descriptors (`x`).\r\n */\r\n width?: number;\r\n /** Device breakpoints for viewport-based sizing (default: DEFAULT_DEVICE_BREAKPOINTS) */\r\n deviceBreakpoints?: number[];\r\n /** Image breakpoints for smaller images (default: DEFAULT_IMAGE_BREAKPOINTS) */\r\n imageBreakpoints?: number[];\r\n /** Base transformation options to apply to all variants */\r\n transformations?: TransformationOptions;\r\n /** Whether to use short or long parameter names (default: 'short') */\r\n mode?: NameMode;\r\n}\r\n\r\n/**\r\n * Result of responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageResult {\r\n /** The src attribute value (largest/default variant) */\r\n src: string;\r\n /** The srcset attribute value */\r\n srcSet?: string;\r\n /** The sizes attribute value (for width descriptors) */\r\n sizes?: string;\r\n /** The width attribute value (when explicitly provided) */\r\n width?: number;\r\n}\r\n\r\n/**\r\n * Computes candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction computeCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr\r\n } = params;\r\n\r\n // ---- Normalize & guard ----\r\n const sortedAll = [...new Set(allBreakpoints)].sort((a, b) => a - b);\r\n const sortedDevice = [...new Set(deviceBreakpoints)].sort((a, b) => a - b);\r\n\r\n if (!sortedAll.length || !sortedDevice.length) {\r\n return { candidates: [], descriptor: 'w' };\r\n }\r\n\r\n const minDevice = sortedDevice[0]!;\r\n const maxDevice = sortedDevice[sortedDevice.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n // Explicit width (fixed layout) → x descriptors ----\r\n // Prefer this when layout width is known and sizes does NOT imply vw scaling\r\n if (typeof explicitWidth === 'number' && !hasVW) {\r\n const DPRs = [1, 2, 3];\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(sortedAll, explicitWidth * dpr))\r\n .map(clampMax)\r\n )\r\n ).filter(w => w <= MAX_IMAGE_WIDTH);\r\n\r\n return {\r\n candidates,\r\n descriptor: 'x'\r\n };\r\n }\r\n\r\n // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const minRatio = Math.min(...vwRatios);\r\n const maxRatio = Math.max(...vwRatios);\r\n\r\n const minPx = minDevice * minRatio;\r\n const maxPx = maxDevice * maxRatio * DEFAULT_MAX_DPR;\r\n\r\n const candidates = sortedAll.filter(\r\n w => w >= minPx && w <= clampMax(maxPx)\r\n );\r\n\r\n return {\r\n candidates,\r\n descriptor: 'w'\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const maxUseful = maxDevice * DEFAULT_MAX_DPR;\r\n\r\n return {\r\n candidates: sortedAll.filter(w => w <= clampMax(maxUseful)),\r\n descriptor: 'w'\r\n };\r\n}\r\n\r\n/**\r\n * Generates responsive image attributes (src, srcSet, sizes) for optimal loading.\r\n *\r\n * Supports two strategies:\r\n * 1. **Responsive (with `sizes`)**: Uses width descriptors (`w`) for fluid layouts\r\n * where image size varies with viewport.\r\n * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size\r\n * images that need high-DPI support.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - Options for responsive image generation\r\n * @returns Object containing src, srcSet, and optionally sizes attributes\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/photo.jpg' };\r\n *\r\n * // Responsive image with sizes attribute (uses `w` descriptors)\r\n * createResponsiveAttributes(config, { sizes: '(max-width: 768px) 100vw, 50vw' });\r\n * // => {\r\n * // src: '...?w=3840',\r\n * // srcSet: '...?w=640 640w, ...?w=750 750w, ..., ...?w=3840 3840w',\r\n * // sizes: '(max-width: 768px) 100vw, 50vw'\r\n * // }\r\n *\r\n * // Fixed-width image (uses `x` descriptors)\r\n * createResponsiveAttributes(config, { width: 400 });\r\n * // => {\r\n * // src: '...?w=384',\r\n * // srcSet: '...?w=384 1x, ...?w=828 2x',\r\n * // width: 400\r\n * // }\r\n *\r\n * // With transformations\r\n * createResponsiveAttributes(config, {\r\n * sizes: '100vw',\r\n * transformations: { format: 'WEBP', quality: 80 }\r\n * });\r\n * ```\r\n */\r\nexport const createResponsiveAttributes = (\r\n config: UrlBuilderConfig,\r\n options: ResponsiveImageOptions = {}\r\n): ResponsiveImageResult => {\r\n const {\r\n sizes,\r\n width,\r\n deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],\r\n imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],\r\n transformations = {},\r\n mode = 'short',\r\n } = options;\r\n\r\n const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);\r\n const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);\r\n\r\n const allBreakpoints = [...new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);\r\n\r\n const { candidates, descriptor } = computeCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(width !== undefined && { explicitWidth: width }),\r\n ...(sizes !== undefined && { sizesAttr: sizes }),\r\n });\r\n\r\n if (candidates.length === 0) {\r\n // Fallback: no valid candidates, return base URL\r\n return { src: config.baseUrl };\r\n }\r\n\r\n // Build srcSet entries\r\n const srcSetEntries = candidates.map((w, index,) => buildSrcEntries(w, index, config, transformations, mode, descriptor));\r\n\r\n // Default src is the largest candidate\r\n const largestWidth = candidates[candidates.length - 1]!;\r\n const src = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: largestWidth },\r\n mode\r\n );\r\n\r\n const endSizes = sizes ?? (descriptor === 'w' ? '100vw' : undefined);\r\n\r\n return {\r\n src,\r\n ...(endSizes ? { sizes: endSizes } : {}),\r\n srcSet: srcSetEntries.join(', '),\r\n ...(width !== undefined ? { width } : {}),\r\n };\r\n};\r\n\r\nfunction buildSrcEntries(width: number, index: number, config: UrlBuilderConfig, transformations: TransformationOptions, mode: NameMode, descriptor: 'w' | 'x'): string {\r\n const url = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: width },\r\n mode\r\n );\r\n\r\n const desc = descriptor === 'w' ? `${width}w` : `${index + 1}x`;\r\n\r\n return `${url} ${desc}`;\r\n}\r\n","import { Path, PathValue } from './util-types';\r\nimport { MAX_IMAGE_WIDTH } from './src-set';\r\n\r\nexport const normalizeHex = (value: string) => value.replace('#', '')\r\n\r\n\r\nexport const removeTrailingSlash = (baseUrl: string) => {\r\n return baseUrl.endsWith('/')\r\n ? baseUrl.slice(0, -1)\r\n : baseUrl;\r\n}\r\n\r\nexport const getNestedValue = <\r\n T,\r\n P extends Path<T>\r\n>(\r\n obj: T,\r\n path: P\r\n): PathValue<T, P> | undefined =>\r\n path.reduce<any>(\r\n (acc, key) => (acc == null ? undefined : acc[key]),\r\n obj\r\n );\r\n\r\n\r\nexport const clampMax = (v: number) => Math.min(v, MAX_IMAGE_WIDTH);\r\n\r\nexport const nearest = (sortedBreakpoints: number[],target: number) =>\r\n sortedBreakpoints.find(w => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1]!;\r\n\r\nexport const parseVW = (sizes?: string): number[] => {\r\n if (!sizes) return [];\r\n return [...sizes.matchAll(/(\\d+(?:\\.\\d+)?)vw/g)].map(\r\n m => Number(m[1]) / 100\r\n );\r\n};\r\n\r\n","import { ParamSpec, Path } from './util-types';\r\nimport { TransformationOptions } from './types';\r\nimport { normalizeHex } from './utils';\r\n\r\nexport const PARAMS = [\r\n {path: ['width'], long: 'width', short: 'w'},\r\n {path: ['height'], long: 'height', short: 'h'},\r\n {path: ['dpr'], long: 'dpr', short: 'dpr'},\r\n {path: ['mode'], long: 'mode', short: 'rm'},\r\n {\r\n path: ['background'],\r\n long: 'background',\r\n short: 'bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n\r\n {path: ['format'], long: 'format', short: 'f'},\r\n {path: ['quality'], long: 'quality', short: 'q'},\r\n {path: ['stripMetadata'], long: 'stripMetadata', short: 'st'},\r\n\r\n {path: ['blur'], long: 'blur', short: 'bl'},\r\n {path: ['brightness'], long: 'brightness', short: 'br'},\r\n {path: ['contrast'], long: 'contrast', short: 'ct'},\r\n {path: ['grayscale'], long: 'grayscale', short: 'gs'},\r\n {path: ['saturation'], long: 'saturation', short: 'sa'},\r\n {path: ['sepia'], long: 'sepia', short: 'sp'},\r\n {path: ['sharpen'], long: 'sharpen', short: 'sh'},\r\n {path: ['noise'], long: 'noise', short: 'ns'},\r\n {path: ['rotate'], long: 'rotate', short: 'rt'},\r\n\r\n {path: ['border', 'width'], long: 'border.width', short: 'bo.w'},\r\n {\r\n path: ['border', 'color'],\r\n long: 'border.color',\r\n short: 'bo.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['border', 'radius'], long: 'border.radius', short: 'bo.r'},\r\n\r\n {path: ['crop', 'type'], long: 'crop.type', short: 'cr.t'},\r\n {path: ['crop', 'objectType'], long: 'crop.objectType', short: 'cr.o'},\r\n {path: ['crop', 'focus', 'position', 'x'], long: 'crop.x', short: 'cr.x'},\r\n {path: ['crop', 'focus', 'position', 'y'], long: 'crop.y', short: 'cr.y'},\r\n {path: ['crop', 'focus', 'strategy'], long: 'crop', short: 'cr'},\r\n {path: ['crop', 'width'], long: 'crop.width', short: 'cr.w'},\r\n {path: ['crop', 'height'], long: 'crop.height', short: 'cr.h'},\r\n {path: ['crop', 'afterResize'], long: 'crop.afterResize', short: 'cr.ar'},\r\n\r\n {path: ['text', 'text'], long: 'text', short: 'tx'},\r\n {\r\n path: ['text', 'color'],\r\n long: 'text.color',\r\n short: 'tx.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'opacity'], long: 'text.opacity', short: 'tx.o'},\r\n {path: ['text', 'size'], long: 'text.size', short: 'tx.s'},\r\n {path: ['text', 'font'], long: 'text.font', short: 'tx.f'},\r\n {path: ['text', 'fontSize'], long: 'text.fontSize', short: 'tx.fs'},\r\n {path: ['text', 'position'], long: 'text.position', short: 'tx.p'},\r\n {\r\n path: ['text', 'background'],\r\n long: 'text.background',\r\n short: 'tx.bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'backgroundOpacity'], long: 'text.backgroundOpacity', short: 'tx.bg.o'},\r\n\r\n {path: ['watermark', 'name'], long: 'watermark', short: 'wm'},\r\n {path: ['watermark', 'opacity'], long: 'watermark.opacity', short: 'wm.o'},\r\n {path: ['watermark', 'size'], long: 'watermark.size', short: 'wm.s'},\r\n {path: ['watermark', 'width'], long: 'watermark.width', short: 'wm.w'},\r\n {path: ['watermark', 'height'], long: 'watermark.height', short: 'wm.h'},\r\n {path: ['watermark', 'position'], long: 'watermark.position', short: 'wm.p'},\r\n] as const satisfies readonly ParamSpec<\r\n TransformationOptions,\r\n Path<TransformationOptions>\r\n>[];\r\n","import { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { getNestedValue, removeTrailingSlash } from './utils';\r\nimport { PARAMS } from './config';\r\n\r\n/**\r\n * Determines which parameter names to use in the query string.\r\n * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)\r\n * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)\r\n */\r\nexport type NameMode = 'short' | 'long';\r\n\r\n/**\r\n * Converts transformation options into a URL-encoded query string.\r\n *\r\n * Iterates through all defined parameters in the PARAMS config, extracts values\r\n * from the options object using their paths, applies any normalization functions\r\n * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.\r\n *\r\n * @param options - The transformation options object\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns URL-encoded query string (without leading `?`)\r\n *\r\n * @example\r\n * ```ts\r\n * // Using short aliases (default)\r\n * buildQueryParams({ width: 800, height: 600, quality: 80 });\r\n * // => 'w=800&h=600&q=80'\r\n *\r\n * // Using long parameter names\r\n * buildQueryParams({ width: 800, format: 'webp' }, 'long');\r\n * // => 'width=800&format=webp'\r\n *\r\n * // Nested options\r\n * buildQueryParams({ border: { width: 2, color: '#ff0000' } });\r\n * // => 'bo.w=2&bo.c=ff0000'\r\n * ```\r\n */\r\nexport const buildTransformationQueryParams = (\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n): string => {\r\n const params: Array<[string, string]> = [];\r\n\r\n for (const spec of PARAMS) {\r\n const value = getNestedValue(options, spec.path);\r\n if (value == null) continue;\r\n\r\n const name =\r\n mode === 'short' && spec.short ? spec.short : spec.long;\r\n\r\n let normalized = value\r\n if ('normalize' in spec) {\r\n normalized = spec.normalize(value)\r\n }\r\n\r\n params.push([name, String(normalized)]);\r\n }\r\n\r\n\r\n return new URLSearchParams(\r\n params.map(([k, v]) => [k, v])\r\n ).toString();\r\n\r\n};\r\n\r\n/**\r\n * Builds a complete transformation URL from a base URL and transformation options.\r\n *\r\n * Combines the configured base URL with query parameters generated from the\r\n * transformation options. Handles the special `original` flag which returns\r\n * the unmodified source image.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - The transformation options to apply\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns The complete URL string with query parameters\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://example.com/images/photo.jpg?w=400&h=300'\r\n *\r\n * // Multiple transformations\r\n * buildTransformationUrl(config, {\r\n * width: 800,\r\n * format: 'webp',\r\n * quality: 85,\r\n * blur: 5\r\n * });\r\n * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'\r\n *\r\n * // Request original image (no transformations)\r\n * buildTransformationUrl(config, { original: true });\r\n * // => 'https://example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://example.com/images/photo.jpg?width=400'\r\n * ```\r\n */\r\n/**\r\n * Extracts the base URL path without query parameters\r\n */\r\nconst getBaseUrlWithoutQuery = (url: string): string => {\r\n const queryIndex = url.indexOf('?');\r\n return queryIndex === -1 ? url : url.slice(0, queryIndex);\r\n};\r\n\r\nexport const buildTransformationUrl = (\r\n config: UrlBuilderConfig,\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n) => {\r\n // Strip any existing query params from baseUrl - transformations replace them\r\n const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));\r\n\r\n if (options.original) {\r\n return `${baseUrl}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(options, mode);\r\n\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/src-set.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":";AAOO,IAAM,eAAA,GAAkB,IAAA;AAKxB,IAAM,0BAAA,GAA6B;AAAA,EACtC,GAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA;AACJ,CAAA;AAKO,IAAM,yBAAA,GAA4B,CAAC,EAAA,EAAI,EAAA,EAAI,IAAI,EAAA,EAAI,EAAA,EAAI,GAAA,EAAK,GAAA,EAAK,GAAG,CAAA;AA2C3E,IAAM,eAAA,GAAkB,CAAA;AAExB,SAAS,uBAAuB,MAAA,EAKoB;AAChD,EAAA,MAAM;AAAA,IACF,cAAA;AAAA,IACA,iBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACJ,GAAI,MAAA;AAGJ,EAAA,MAAM,SAAA,GAAY,CAAC,GAAG,IAAI,GAAA,CAAI,cAAc,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AACnE,EAAA,MAAM,YAAA,GAAe,CAAC,GAAG,IAAI,GAAA,CAAI,iBAAiB,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AAEzE,EAAA,IAAI,CAAC,SAAA,CAAU,MAAA,IAAU,CAAC,aAAa,MAAA,EAAQ;AAC3C,IAAA,OAAO,EAAE,UAAA,EAAY,EAAC,EAAG,YAAY,GAAA,EAAI;AAAA,EAC7C;AAEA,EAAA,MAAM,SAAA,GAAY,aAAa,CAAC,CAAA;AAChC,EAAA,MAAM,SAAA,GAAY,YAAA,CAAa,YAAA,CAAa,MAAA,GAAS,CAAC,CAAA;AAEtD,EAAA,MAAM,QAAA,GAAW,QAAQ,SAAS,CAAA;AAClC,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,GAAS,CAAA;AAIhC,EAAA,IAAI,OAAO,aAAA,KAAkB,QAAA,IAAY,CAAC,KAAA,EAAO;AAC7C,IAAA,MAAM,IAAA,GAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAErB,IAAA,MAAM,aAAa,KAAA,CAAM,IAAA;AAAA,MACrB,IAAI,GAAA;AAAA,QACA,IAAA,CACK,GAAA,CAAI,CAAA,GAAA,KAAO,OAAA,CAAQ,SAAA,EAAW,gBAAgB,GAAG,CAAC,CAAA,CAClD,GAAA,CAAI,QAAQ;AAAA;AACrB,KACJ,CAAE,MAAA,CAAO,CAAA,CAAA,KAAK,CAAA,IAAK,eAAe,CAAA;AAElC,IAAA,OAAO;AAAA,MACH,UAAA;AAAA,MACA,UAAA,EAAY;AAAA,KAChB;AAAA,EACJ;AAGA,EAAA,IAAI,KAAA,EAAO;AACP,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,GAAG,QAAQ,CAAA;AACrC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,GAAG,QAAQ,CAAA;AAErC,IAAA,MAAM,QAAQ,SAAA,GAAY,QAAA;AAC1B,IAAA,MAAM,KAAA,GAAQ,YAAY,QAAA,GAAW,eAAA;AAErC,IAAA,MAAM,aAAa,SAAA,CAAU,MAAA;AAAA,MACzB,CAAA,CAAA,KAAK,CAAA,IAAK,KAAA,IAAS,CAAA,IAAK,SAAS,KAAK;AAAA,KAC1C;AAEA,IAAA,OAAO;AAAA,MACH,UAAA;AAAA,MACA,UAAA,EAAY;AAAA,KAChB;AAAA,EACJ;AAGA,EAAA,MAAM,YAAY,SAAA,GAAY,eAAA;AAE9B,EAAA,OAAO;AAAA,IACH,YAAY,SAAA,CAAU,MAAA,CAAO,OAAK,CAAA,IAAK,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IAC1D,UAAA,EAAY;AAAA,GAChB;AACJ;AA0CO,IAAM,0BAAA,GAA6B,CACtC,MAAA,EACA,OAAA,GAAkC,EAAC,KACX;AACxB,EAAA,MAAM;AAAA,IACF,KAAA;AAAA,IACA,KAAA;AAAA,IACA,iBAAA,GAAoB,CAAC,GAAG,0BAA0B,CAAA;AAAA,IAClD,gBAAA,GAAmB,CAAC,GAAG,yBAAyB,CAAA;AAAA,IAChD,kBAAkB,EAAC;AAAA,IACnB,IAAA,GAAO;AAAA,GACX,GAAI,OAAA;AAGJ,EAAA,MAAM,SAAA,GAAY,gBAAgB,KAAA,IAAS,KAAA;AAE3C,EAAA,MAAM,uBAAA,GAA0B,CAAC,GAAG,iBAAiB,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAC3E,EAAA,MAAM,sBAAA,GAAyB,CAAC,GAAG,gBAAgB,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAEzE,EAAA,MAAM,iBAAiB,CAAC,uBAAO,GAAA,CAAI,CAAC,GAAG,sBAAA,EAAwB,GAAG,uBAAuB,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AAEjH,EAAA,MAAM,EAAE,UAAA,EAAY,UAAA,EAAW,GAAI,sBAAA,CAAuB;AAAA,IACtD,cAAA;AAAA,IACA,iBAAA,EAAmB,uBAAA;AAAA,IACnB,GAAI,SAAA,KAAc,MAAA,IAAa,EAAE,eAAe,SAAA,EAAU;AAAA,IAC1D,GAAI,KAAA,KAAU,MAAA,IAAa,EAAE,WAAW,KAAA;AAAM,GACjD,CAAA;AAED,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAEzB,IAAA,OAAO,EAAE,GAAA,EAAK,MAAA,CAAO,OAAA,EAAQ;AAAA,EACjC;AAGA,EAAA,MAAM,aAAA,GAAgB,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,EAAG,KAAA,KAAW,eAAA,CAAgB,CAAA,EAAG,KAAA,EAAO,MAAA,EAAQ,eAAA,EAAiB,IAAA,EAAM,UAAU,CAAC,CAAA;AAGxH,EAAA,MAAM,YAAA,GAAe,UAAA,CAAW,UAAA,CAAW,MAAA,GAAS,CAAC,CAAA;AACrD,EAAA,MAAM,GAAA,GAAM,sBAAA;AAAA,IACR,MAAA;AAAA,IACA,EAAE,GAAG,eAAA,EAAiB,KAAA,EAAO,YAAA,EAAa;AAAA,IAC1C;AAAA,GACJ;AAEA,EAAA,MAAM,QAAA,GAAW,KAAA,KAAU,UAAA,KAAe,GAAA,GAAM,OAAA,GAAU,MAAA,CAAA;AAE1D,EAAA,OAAO;AAAA,IACH,GAAA;AAAA,IACA,GAAI,QAAA,GAAW,EAAE,KAAA,EAAO,QAAA,KAAa,EAAC;AAAA,IACtC,MAAA,EAAQ,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA;AAAA,IAC/B,GAAI,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,KAAU;AAAC,GAC3C;AACJ;AAEA,SAAS,gBAAgB,KAAA,EAAe,KAAA,EAAe,MAAA,EAA0B,eAAA,EAAwC,MAAgB,UAAA,EAA+B;AACpK,EAAA,MAAM,GAAA,GAAM,sBAAA;AAAA,IACR,MAAA;AAAA,IACA,EAAE,GAAG,eAAA,EAAiB,KAAA,EAAa;AAAA,IACnC;AAAA,GACJ;AAEA,EAAA,MAAM,IAAA,GAAO,eAAe,GAAA,GAAM,CAAA,EAAG,KAAK,CAAA,CAAA,CAAA,GAAM,CAAA,EAAG,QAAQ,CAAC,CAAA,CAAA,CAAA;AAE5D,EAAA,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AACzB;;;ACrPO,IAAM,eAAe,CAAC,KAAA,KAAkB,KAAA,CAAM,OAAA,CAAQ,KAAK,EAAE,CAAA;AAG7D,IAAM,mBAAA,GAAsB,CAAC,OAAA,KAAoB;AACpD,EAAA,OAAO,OAAA,CAAQ,SAAS,GAAG,CAAA,GACrB,QAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GACnB,OAAA;AACV,CAAA;AAEO,IAAM,cAAA,GAAiB,CAI1B,GAAA,EACA,IAAA,KAEA,IAAA,CAAK,MAAA;AAAA,EACD,CAAC,GAAA,EAAK,GAAA,KAAS,OAAO,IAAA,GAAO,MAAA,GAAY,IAAI,GAAG,CAAA;AAAA,EAChD;AACJ,CAAA;AAGG,IAAM,WAAW,CAAC,CAAA,KAAc,IAAA,CAAK,GAAA,CAAI,GAAG,eAAe,CAAA;AAE3D,IAAM,OAAA,GAAU,CAAC,iBAAA,EAA4B,MAAA,KAChD,iBAAA,CAAkB,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,IAAK,MAAM,CAAA,IAAK,iBAAA,CAAkB,iBAAA,CAAkB,SAAS,CAAC,CAAA;AAEvF,IAAM,OAAA,GAAU,CAAC,KAAA,KAA6B;AACjD,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AACpB,EAAA,OAAO,CAAC,GAAG,KAAA,CAAM,QAAA,CAAS,oBAAoB,CAAC,CAAA,CAAE,GAAA;AAAA,IAC7C,CAAA,CAAA,KAAK,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI;AAAA,GACxB;AACJ,CAAA;;;AC/BO,IAAM,MAAA,GAAS;AAAA,EAClB,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,GAAA,EAAG;AAAA,EAC3C,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,GAAA,EAAG;AAAA,EAC7C,EAAC,MAAM,CAAC,KAAK,GAAG,IAAA,EAAM,KAAA,EAAO,OAAO,KAAA,EAAK;AAAA,EACzC,EAAC,MAAM,CAAC,MAAM,GAAG,IAAA,EAAM,MAAA,EAAQ,OAAO,IAAA,EAAI;AAAA,EAC1C;AAAA,IACI,IAAA,EAAM,CAAC,YAAY,CAAA;AAAA,IACnB,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,IAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EAEA,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,GAAA,EAAG;AAAA,EAC7C,EAAC,MAAM,CAAC,SAAS,GAAG,IAAA,EAAM,SAAA,EAAW,OAAO,GAAA,EAAG;AAAA,EAC/C,EAAC,MAAM,CAAC,eAAe,GAAG,IAAA,EAAM,eAAA,EAAiB,OAAO,IAAA,EAAI;AAAA,EAE5D,EAAC,MAAM,CAAC,MAAM,GAAG,IAAA,EAAM,MAAA,EAAQ,OAAO,IAAA,EAAI;AAAA,EAC1C,EAAC,MAAM,CAAC,YAAY,GAAG,IAAA,EAAM,YAAA,EAAc,OAAO,IAAA,EAAI;AAAA,EACtD,EAAC,MAAM,CAAC,UAAU,GAAG,IAAA,EAAM,UAAA,EAAY,OAAO,IAAA,EAAI;AAAA,EAClD,EAAC,MAAM,CAAC,WAAW,GAAG,IAAA,EAAM,WAAA,EAAa,OAAO,IAAA,EAAI;AAAA,EACpD,EAAC,MAAM,CAAC,YAAY,GAAG,IAAA,EAAM,YAAA,EAAc,OAAO,IAAA,EAAI;AAAA,EACtD,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,IAAA,EAAI;AAAA,EAC5C,EAAC,MAAM,CAAC,SAAS,GAAG,IAAA,EAAM,SAAA,EAAW,OAAO,IAAA,EAAI;AAAA,EAChD,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,IAAA,EAAI;AAAA,EAC5C,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,IAAA,EAAI;AAAA,EAE9C,EAAC,MAAM,CAAC,QAAA,EAAU,OAAO,CAAA,EAAG,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAO,MAAA,EAAM;AAAA,EAC/D;AAAA,IACI,IAAA,EAAM,CAAC,QAAA,EAAU,OAAO,CAAA;AAAA,IACxB,IAAA,EAAM,cAAA;AAAA,IACN,KAAA,EAAO,MAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,QAAA,EAAU,QAAQ,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,MAAA,EAAM;AAAA,EAEjE,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,YAAY,CAAA,EAAG,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,MAAA,EAAM;AAAA,EACrE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAA,EAAY,GAAG,CAAA,EAAG,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,MAAA,EAAM;AAAA,EACxE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAA,EAAY,GAAG,CAAA,EAAG,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,MAAA,EAAM;AAAA,EACxE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAU,CAAA,EAAG,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAI;AAAA,EAC/D,EAAC,MAAM,CAAC,MAAA,EAAQ,OAAO,CAAA,EAAG,IAAA,EAAM,YAAA,EAAc,KAAA,EAAO,MAAA,EAAM;AAAA,EAC3D,EAAC,MAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA,EAAG,IAAA,EAAM,aAAA,EAAe,KAAA,EAAO,MAAA,EAAM;AAAA,EAC7D,EAAC,MAAM,CAAC,MAAA,EAAQ,aAAa,CAAA,EAAG,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,OAAA,EAAO;AAAA,EAExE,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAI;AAAA,EAClD;AAAA,IACI,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAO,CAAA;AAAA,IACtB,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,MAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,EAAG,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAO,MAAA,EAAM;AAAA,EAC/D,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,UAAU,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,OAAA,EAAO;AAAA,EAClE,EAAC,MAAM,CAAC,MAAA,EAAQ,UAAU,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,MAAA,EAAM;AAAA,EACjE;AAAA,IACI,IAAA,EAAM,CAAC,MAAA,EAAQ,YAAY,CAAA;AAAA,IAC3B,IAAA,EAAM,iBAAA;AAAA,IACN,KAAA,EAAO,OAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,MAAA,EAAQ,mBAAmB,CAAA,EAAG,IAAA,EAAM,wBAAA,EAA0B,KAAA,EAAO,SAAA,EAAS;AAAA,EAEtF,EAAC,MAAM,CAAC,WAAA,EAAa,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,IAAA,EAAI;AAAA,EAC5D,EAAC,MAAM,CAAC,WAAA,EAAa,SAAS,CAAA,EAAG,IAAA,EAAM,mBAAA,EAAqB,KAAA,EAAO,MAAA,EAAM;AAAA,EACzE,EAAC,MAAM,CAAC,WAAA,EAAa,MAAM,CAAA,EAAG,IAAA,EAAM,gBAAA,EAAkB,KAAA,EAAO,MAAA,EAAM;AAAA,EACnE,EAAC,MAAM,CAAC,WAAA,EAAa,OAAO,CAAA,EAAG,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,MAAA,EAAM;AAAA,EACrE,EAAC,MAAM,CAAC,WAAA,EAAa,QAAQ,CAAA,EAAG,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,MAAA,EAAM;AAAA,EACvE,EAAC,MAAM,CAAC,WAAA,EAAa,UAAU,CAAA,EAAG,IAAA,EAAM,oBAAA,EAAsB,KAAA,EAAO,MAAA;AACzE,CAAA;;;ACrCO,IAAM,8BAAA,GAAiC,CAC1C,OAAA,EACA,IAAA,GAAiB,OAAA,KACR;AACT,EAAA,MAAM,SAAkC,EAAC;AAEzC,EAAA,KAAA,MAAW,QAAQ,MAAA,EAAQ;AACvB,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,OAAA,EAAS,IAAA,CAAK,IAAI,CAAA;AAC/C,IAAA,IAAI,SAAS,IAAA,EAAM;AAEnB,IAAA,MAAM,OACF,IAAA,KAAS,OAAA,IAAW,KAAK,KAAA,GAAQ,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA;AAEvD,IAAA,IAAI,UAAA,GAAa,KAAA;AACjB,IAAA,IAAI,eAAe,IAAA,EAAM;AACrB,MAAA,UAAA,GAAa,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,IACrC;AAEA,IAAA,MAAA,CAAO,KAAK,CAAC,IAAA,EAAM,MAAA,CAAO,UAAU,CAAC,CAAC,CAAA;AAAA,EAC1C;AAGA,EAAA,OAAO,IAAI,eAAA;AAAA,IACP,MAAA,CAAO,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAC,CAAA,EAAG,CAAC,CAAC;AAAA,IAC/B,QAAA,EAAS;AAEf;AA2CA,IAAM,sBAAA,GAAyB,CAAC,GAAA,KAAwB;AACpD,EAAA,MAAM,UAAA,GAAa,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAClC,EAAA,OAAO,eAAe,EAAA,GAAK,GAAA,GAAM,GAAA,CAAI,KAAA,CAAM,GAAG,UAAU,CAAA;AAC5D,CAAA;AAEO,IAAM,sBAAA,GAAyB,CAClC,MAAA,EACA,OAAA,EACA,OAAiB,OAAA,KAChB;AAED,EAAA,MAAM,OAAA,GAAU,mBAAA,CAAoB,sBAAA,CAAuB,MAAA,CAAO,OAAO,CAAC,CAAA;AAE1E,EAAA,IAAI,QAAQ,QAAA,EAAU;AAClB,IAAA,OAAO,GAAG,OAAO,CAAA,SAAA,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,KAAA,GAAQ,8BAAA,CAA+B,OAAA,EAAS,IAAI,CAAA;AAE1D,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAC9B","file":"index.js","sourcesContent":["import { buildTransformationUrl, NameMode } from './url-builder';\r\nimport { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { clampMax, nearest, parseVW } from './utils';\r\n\r\n/**\r\n * Maximum supported image width\r\n */\r\nexport const MAX_IMAGE_WIDTH = 4096;\r\n\r\n/**\r\n * Default device breakpoints for responsive srcset generation\r\n */\r\nexport const DEFAULT_DEVICE_BREAKPOINTS = [\r\n 320,\r\n 375,\r\n 640,\r\n 768,\r\n 1024,\r\n 1280,\r\n 1536,\r\n 1920\r\n] as const;\r\n\r\n/**\r\n * Default image breakpoints for smaller images (icons, thumbnails)\r\n */\r\nexport const DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384] as const;\r\n\r\n/**\r\n * Options for responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageOptions {\r\n /**\r\n * The `sizes` attribute value (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * When provided, generates width descriptors (`w`) for responsive layouts.\r\n */\r\n sizes?: string;\r\n /**\r\n * Fixed display width in CSS pixels.\r\n * When provided without `sizes`, generates DPR descriptors (`x`).\r\n */\r\n width?: number;\r\n /** Device breakpoints for viewport-based sizing (default: DEFAULT_DEVICE_BREAKPOINTS) */\r\n deviceBreakpoints?: number[];\r\n /** Image breakpoints for smaller images (default: DEFAULT_IMAGE_BREAKPOINTS) */\r\n imageBreakpoints?: number[];\r\n /** Base transformation options to apply to all variants */\r\n transformations?: TransformationOptions;\r\n /** Whether to use short or long parameter names (default: 'short') */\r\n mode?: NameMode;\r\n}\r\n\r\n/**\r\n * Result of responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageResult {\r\n /** The src attribute value (largest/default variant) */\r\n src: string;\r\n /** The srcset attribute value */\r\n srcSet?: string;\r\n /** The sizes attribute value (for width descriptors) */\r\n sizes?: string;\r\n /** The width attribute value (when explicitly provided) */\r\n width?: number;\r\n}\r\n\r\n/**\r\n * Computes candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction computeCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr\r\n } = params;\r\n\r\n // ---- Normalize & guard ----\r\n const sortedAll = [...new Set(allBreakpoints)].sort((a, b) => a - b);\r\n const sortedDevice = [...new Set(deviceBreakpoints)].sort((a, b) => a - b);\r\n\r\n if (!sortedAll.length || !sortedDevice.length) {\r\n return { candidates: [], descriptor: 'w' };\r\n }\r\n\r\n const minDevice = sortedDevice[0]!;\r\n const maxDevice = sortedDevice[sortedDevice.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n // Explicit width (fixed layout) → x descriptors ----\r\n // Prefer this when layout width is known and sizes does NOT imply vw scaling\r\n if (typeof explicitWidth === 'number' && !hasVW) {\r\n const DPRs = [1, 2, 3];\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(sortedAll, explicitWidth * dpr))\r\n .map(clampMax)\r\n )\r\n ).filter(w => w <= MAX_IMAGE_WIDTH);\r\n\r\n return {\r\n candidates,\r\n descriptor: 'x'\r\n };\r\n }\r\n\r\n // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const minRatio = Math.min(...vwRatios);\r\n const maxRatio = Math.max(...vwRatios);\r\n\r\n const minPx = minDevice * minRatio;\r\n const maxPx = maxDevice * maxRatio * DEFAULT_MAX_DPR;\r\n\r\n const candidates = sortedAll.filter(\r\n w => w >= minPx && w <= clampMax(maxPx)\r\n );\r\n\r\n return {\r\n candidates,\r\n descriptor: 'w'\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const maxUseful = maxDevice * DEFAULT_MAX_DPR;\r\n\r\n return {\r\n candidates: sortedAll.filter(w => w <= clampMax(maxUseful)),\r\n descriptor: 'w'\r\n };\r\n}\r\n\r\n/**\r\n * Generates responsive image attributes (src, srcSet, sizes) for optimal loading.\r\n *\r\n * Supports two strategies:\r\n * 1. **Responsive (with `sizes`)**: Uses width descriptors (`w`) for fluid layouts\r\n * where image size varies with viewport.\r\n * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size\r\n * images that need high-DPI support.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - Options for responsive image generation\r\n * @returns Object containing src, srcSet, and optionally sizes attributes\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/photo.jpg' };\r\n *\r\n * // Responsive image with sizes attribute (uses `w` descriptors)\r\n * createResponsiveAttributes(config, { sizes: '(max-width: 768px) 100vw, 50vw' });\r\n * // => {\r\n * // src: '...?w=3840',\r\n * // srcSet: '...?w=640 640w, ...?w=750 750w, ..., ...?w=3840 3840w',\r\n * // sizes: '(max-width: 768px) 100vw, 50vw'\r\n * // }\r\n *\r\n * // Fixed-width image (uses `x` descriptors)\r\n * createResponsiveAttributes(config, { width: 400 });\r\n * // => {\r\n * // src: '...?w=384',\r\n * // srcSet: '...?w=384 1x, ...?w=828 2x',\r\n * // width: 400\r\n * // }\r\n *\r\n * // With transformations\r\n * createResponsiveAttributes(config, {\r\n * sizes: '100vw',\r\n * transformations: { format: 'WEBP', quality: 80 }\r\n * });\r\n * ```\r\n */\r\nexport const createResponsiveAttributes = (\r\n config: UrlBuilderConfig,\r\n options: ResponsiveImageOptions = {}\r\n): ResponsiveImageResult => {\r\n const {\r\n sizes,\r\n width,\r\n deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],\r\n imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],\r\n transformations = {},\r\n mode = 'short',\r\n } = options;\r\n\r\n // If transformations.width is set, it takes precedence as the base width\r\n const baseWidth = transformations.width ?? width;\r\n\r\n const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);\r\n const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);\r\n\r\n const allBreakpoints = [...new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);\r\n\r\n const { candidates, descriptor } = computeCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(baseWidth !== undefined && { explicitWidth: baseWidth }),\r\n ...(sizes !== undefined && { sizesAttr: sizes }),\r\n });\r\n\r\n if (candidates.length === 0) {\r\n // Fallback: no valid candidates, return base URL\r\n return { src: config.baseUrl };\r\n }\r\n\r\n // Build srcSet entries\r\n const srcSetEntries = candidates.map((w, index,) => buildSrcEntries(w, index, config, transformations, mode, descriptor));\r\n\r\n // Default src is the largest candidate\r\n const largestWidth = candidates[candidates.length - 1]!;\r\n const src = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: largestWidth },\r\n mode\r\n );\r\n\r\n const endSizes = sizes ?? (descriptor === 'w' ? '100vw' : undefined);\r\n\r\n return {\r\n src,\r\n ...(endSizes ? { sizes: endSizes } : {}),\r\n srcSet: srcSetEntries.join(', '),\r\n ...(width !== undefined ? { width } : {}),\r\n };\r\n};\r\n\r\nfunction buildSrcEntries(width: number, index: number, config: UrlBuilderConfig, transformations: TransformationOptions, mode: NameMode, descriptor: 'w' | 'x'): string {\r\n const url = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: width },\r\n mode\r\n );\r\n\r\n const desc = descriptor === 'w' ? `${width}w` : `${index + 1}x`;\r\n\r\n return `${url} ${desc}`;\r\n}\r\n","import { Path, PathValue } from './util-types';\r\nimport { MAX_IMAGE_WIDTH } from './src-set';\r\n\r\nexport const normalizeHex = (value: string) => value.replace('#', '')\r\n\r\n\r\nexport const removeTrailingSlash = (baseUrl: string) => {\r\n return baseUrl.endsWith('/')\r\n ? baseUrl.slice(0, -1)\r\n : baseUrl;\r\n}\r\n\r\nexport const getNestedValue = <\r\n T,\r\n P extends Path<T>\r\n>(\r\n obj: T,\r\n path: P\r\n): PathValue<T, P> | undefined =>\r\n path.reduce<any>(\r\n (acc, key) => (acc == null ? undefined : acc[key]),\r\n obj\r\n );\r\n\r\n\r\nexport const clampMax = (v: number) => Math.min(v, MAX_IMAGE_WIDTH);\r\n\r\nexport const nearest = (sortedBreakpoints: number[],target: number) =>\r\n sortedBreakpoints.find(w => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1]!;\r\n\r\nexport const parseVW = (sizes?: string): number[] => {\r\n if (!sizes) return [];\r\n return [...sizes.matchAll(/(\\d+(?:\\.\\d+)?)vw/g)].map(\r\n m => Number(m[1]) / 100\r\n );\r\n};\r\n\r\n","import { ParamSpec, Path } from './util-types';\r\nimport { TransformationOptions } from './types';\r\nimport { normalizeHex } from './utils';\r\n\r\nexport const PARAMS = [\r\n {path: ['width'], long: 'width', short: 'w'},\r\n {path: ['height'], long: 'height', short: 'h'},\r\n {path: ['dpr'], long: 'dpr', short: 'dpr'},\r\n {path: ['mode'], long: 'mode', short: 'rm'},\r\n {\r\n path: ['background'],\r\n long: 'background',\r\n short: 'bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n\r\n {path: ['format'], long: 'format', short: 'f'},\r\n {path: ['quality'], long: 'quality', short: 'q'},\r\n {path: ['stripMetadata'], long: 'stripMetadata', short: 'st'},\r\n\r\n {path: ['blur'], long: 'blur', short: 'bl'},\r\n {path: ['brightness'], long: 'brightness', short: 'br'},\r\n {path: ['contrast'], long: 'contrast', short: 'ct'},\r\n {path: ['grayscale'], long: 'grayscale', short: 'gs'},\r\n {path: ['saturation'], long: 'saturation', short: 'sa'},\r\n {path: ['sepia'], long: 'sepia', short: 'sp'},\r\n {path: ['sharpen'], long: 'sharpen', short: 'sh'},\r\n {path: ['noise'], long: 'noise', short: 'ns'},\r\n {path: ['rotate'], long: 'rotate', short: 'rt'},\r\n\r\n {path: ['border', 'width'], long: 'border.width', short: 'bo.w'},\r\n {\r\n path: ['border', 'color'],\r\n long: 'border.color',\r\n short: 'bo.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['border', 'radius'], long: 'border.radius', short: 'bo.r'},\r\n\r\n {path: ['crop', 'type'], long: 'crop.type', short: 'cr.t'},\r\n {path: ['crop', 'objectType'], long: 'crop.objectType', short: 'cr.o'},\r\n {path: ['crop', 'focus', 'position', 'x'], long: 'crop.x', short: 'cr.x'},\r\n {path: ['crop', 'focus', 'position', 'y'], long: 'crop.y', short: 'cr.y'},\r\n {path: ['crop', 'focus', 'strategy'], long: 'crop', short: 'cr'},\r\n {path: ['crop', 'width'], long: 'crop.width', short: 'cr.w'},\r\n {path: ['crop', 'height'], long: 'crop.height', short: 'cr.h'},\r\n {path: ['crop', 'afterResize'], long: 'crop.afterResize', short: 'cr.ar'},\r\n\r\n {path: ['text', 'text'], long: 'text', short: 'tx'},\r\n {\r\n path: ['text', 'color'],\r\n long: 'text.color',\r\n short: 'tx.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'opacity'], long: 'text.opacity', short: 'tx.o'},\r\n {path: ['text', 'size'], long: 'text.size', short: 'tx.s'},\r\n {path: ['text', 'font'], long: 'text.font', short: 'tx.f'},\r\n {path: ['text', 'fontSize'], long: 'text.fontSize', short: 'tx.fs'},\r\n {path: ['text', 'position'], long: 'text.position', short: 'tx.p'},\r\n {\r\n path: ['text', 'background'],\r\n long: 'text.background',\r\n short: 'tx.bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'backgroundOpacity'], long: 'text.backgroundOpacity', short: 'tx.bg.o'},\r\n\r\n {path: ['watermark', 'name'], long: 'watermark', short: 'wm'},\r\n {path: ['watermark', 'opacity'], long: 'watermark.opacity', short: 'wm.o'},\r\n {path: ['watermark', 'size'], long: 'watermark.size', short: 'wm.s'},\r\n {path: ['watermark', 'width'], long: 'watermark.width', short: 'wm.w'},\r\n {path: ['watermark', 'height'], long: 'watermark.height', short: 'wm.h'},\r\n {path: ['watermark', 'position'], long: 'watermark.position', short: 'wm.p'},\r\n] as const satisfies readonly ParamSpec<\r\n TransformationOptions,\r\n Path<TransformationOptions>\r\n>[];\r\n","import { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { getNestedValue, removeTrailingSlash } from './utils';\r\nimport { PARAMS } from './config';\r\n\r\n/**\r\n * Determines which parameter names to use in the query string.\r\n * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)\r\n * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)\r\n */\r\nexport type NameMode = 'short' | 'long';\r\n\r\n/**\r\n * Converts transformation options into a URL-encoded query string.\r\n *\r\n * Iterates through all defined parameters in the PARAMS config, extracts values\r\n * from the options object using their paths, applies any normalization functions\r\n * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.\r\n *\r\n * @param options - The transformation options object\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns URL-encoded query string (without leading `?`)\r\n *\r\n * @example\r\n * ```ts\r\n * // Using short aliases (default)\r\n * buildQueryParams({ width: 800, height: 600, quality: 80 });\r\n * // => 'w=800&h=600&q=80'\r\n *\r\n * // Using long parameter names\r\n * buildQueryParams({ width: 800, format: 'webp' }, 'long');\r\n * // => 'width=800&format=webp'\r\n *\r\n * // Nested options\r\n * buildQueryParams({ border: { width: 2, color: '#ff0000' } });\r\n * // => 'bo.w=2&bo.c=ff0000'\r\n * ```\r\n */\r\nexport const buildTransformationQueryParams = (\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n): string => {\r\n const params: Array<[string, string]> = [];\r\n\r\n for (const spec of PARAMS) {\r\n const value = getNestedValue(options, spec.path);\r\n if (value == null) continue;\r\n\r\n const name =\r\n mode === 'short' && spec.short ? spec.short : spec.long;\r\n\r\n let normalized = value\r\n if ('normalize' in spec) {\r\n normalized = spec.normalize(value)\r\n }\r\n\r\n params.push([name, String(normalized)]);\r\n }\r\n\r\n\r\n return new URLSearchParams(\r\n params.map(([k, v]) => [k, v])\r\n ).toString();\r\n\r\n};\r\n\r\n/**\r\n * Builds a complete transformation URL from a base URL and transformation options.\r\n *\r\n * Combines the configured base URL with query parameters generated from the\r\n * transformation options. Handles the special `original` flag which returns\r\n * the unmodified source image.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - The transformation options to apply\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns The complete URL string with query parameters\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://example.com/images/photo.jpg?w=400&h=300'\r\n *\r\n * // Multiple transformations\r\n * buildTransformationUrl(config, {\r\n * width: 800,\r\n * format: 'webp',\r\n * quality: 85,\r\n * blur: 5\r\n * });\r\n * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'\r\n *\r\n * // Request original image (no transformations)\r\n * buildTransformationUrl(config, { original: true });\r\n * // => 'https://example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://example.com/images/photo.jpg?width=400'\r\n * ```\r\n */\r\n/**\r\n * Extracts the base URL path without query parameters\r\n */\r\nconst getBaseUrlWithoutQuery = (url: string): string => {\r\n const queryIndex = url.indexOf('?');\r\n return queryIndex === -1 ? url : url.slice(0, queryIndex);\r\n};\r\n\r\nexport const buildTransformationUrl = (\r\n config: UrlBuilderConfig,\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n) => {\r\n // Strip any existing query params from baseUrl - transformations replace them\r\n const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));\r\n\r\n if (options.original) {\r\n return `${baseUrl}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(options, mode);\r\n\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
|