@brandlab-digital/site-next 3.12.1 → 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -0
- package/dist/contact/delivery.d.ts +81 -0
- package/dist/contact/delivery.d.ts.map +1 -0
- package/dist/contact/delivery.js +138 -0
- package/dist/contact/delivery.js.map +1 -0
- package/dist/contact/resend-webhook.d.ts +72 -0
- package/dist/contact/resend-webhook.d.ts.map +1 -0
- package/dist/contact/resend-webhook.js +300 -0
- package/dist/contact/resend-webhook.js.map +1 -0
- package/dist/contact/route-handler.d.ts +16 -0
- package/dist/contact/route-handler.d.ts.map +1 -1
- package/dist/contact/route-handler.js +8 -0
- package/dist/contact/route-handler.js.map +1 -1
- package/dist/contact/server-entry.d.ts +2 -0
- package/dist/contact/server-entry.d.ts.map +1 -1
- package/dist/contact/server-entry.js +2 -0
- package/dist/contact/server-entry.js.map +1 -1
- package/dist/contact/server.d.ts +26 -0
- package/dist/contact/server.d.ts.map +1 -1
- package/dist/contact/server.js +48 -3
- package/dist/contact/server.js.map +1 -1
- package/dist/estate-segment.d.ts +48 -0
- package/dist/estate-segment.d.ts.map +1 -0
- package/dist/estate-segment.js +54 -0
- package/dist/estate-segment.js.map +1 -0
- package/dist/google-business-reviews-revalidate.d.ts +61 -0
- package/dist/google-business-reviews-revalidate.d.ts.map +1 -0
- package/dist/google-business-reviews-revalidate.js +151 -0
- package/dist/google-business-reviews-revalidate.js.map +1 -0
- package/dist/google-business-reviews-server.d.ts +21 -2
- package/dist/google-business-reviews-server.d.ts.map +1 -1
- package/dist/google-business-reviews-server.js +21 -4
- package/dist/google-business-reviews-server.js.map +1 -1
- package/dist/headers.d.ts.map +1 -1
- package/dist/headers.js +6 -0
- package/dist/headers.js.map +1 -1
- package/dist/next-config.d.ts +17 -1
- package/dist/next-config.d.ts.map +1 -1
- package/dist/next-config.js +36 -2
- package/dist/next-config.js.map +1 -1
- package/dist/robots.d.ts +26 -4
- package/dist/robots.d.ts.map +1 -1
- package/dist/robots.js +49 -2
- package/dist/robots.js.map +1 -1
- package/dist/ui-kit/brandlab-skin.d.ts +24 -1
- package/dist/ui-kit/brandlab-skin.d.ts.map +1 -1
- package/dist/ui-kit/brandlab-skin.js.map +1 -1
- package/dist/ui-kit/form/photo-upload.d.ts +4 -1
- package/dist/ui-kit/form/photo-upload.d.ts.map +1 -1
- package/dist/ui-kit/form/photo-upload.js +4 -4
- package/dist/ui-kit/form/photo-upload.js.map +1 -1
- package/dist/ui-kit/form/quote-form.d.ts +4 -1
- package/dist/ui-kit/form/quote-form.d.ts.map +1 -1
- package/dist/ui-kit/form/quote-form.js.map +1 -1
- package/dist/ui-kit/form/thank-you.d.ts +4 -1
- package/dist/ui-kit/form/thank-you.d.ts.map +1 -1
- package/dist/ui-kit/form/thank-you.js +2 -2
- package/dist/ui-kit/form/thank-you.js.map +1 -1
- package/dist/ui-kit/icon-glyphs.d.ts +41 -0
- package/dist/ui-kit/icon-glyphs.d.ts.map +1 -0
- package/dist/ui-kit/icon-glyphs.js +138 -0
- package/dist/ui-kit/icon-glyphs.js.map +1 -0
- package/dist/ui-kit/icon-sprite.d.ts +19 -0
- package/dist/ui-kit/icon-sprite.d.ts.map +1 -0
- package/dist/ui-kit/icon-sprite.js +44 -0
- package/dist/ui-kit/icon-sprite.js.map +1 -0
- package/dist/ui-kit/icons.d.ts +38 -3
- package/dist/ui-kit/icons.d.ts.map +1 -1
- package/dist/ui-kit/icons.js +47 -64
- package/dist/ui-kit/icons.js.map +1 -1
- package/dist/ui-kit/prefetch.d.ts +50 -0
- package/dist/ui-kit/prefetch.d.ts.map +1 -0
- package/dist/ui-kit/prefetch.js +50 -0
- package/dist/ui-kit/prefetch.js.map +1 -0
- package/dist/ui-kit/primitives/badge.d.ts +25 -0
- package/dist/ui-kit/primitives/badge.d.ts.map +1 -0
- package/dist/ui-kit/primitives/badge.js +21 -0
- package/dist/ui-kit/primitives/badge.js.map +1 -0
- package/dist/ui-kit/primitives/breadcrumbs.d.ts +27 -0
- package/dist/ui-kit/primitives/breadcrumbs.d.ts.map +1 -0
- package/dist/ui-kit/primitives/breadcrumbs.js +40 -0
- package/dist/ui-kit/primitives/breadcrumbs.js.map +1 -0
- package/dist/ui-kit/primitives/button.d.ts +32 -0
- package/dist/ui-kit/primitives/button.d.ts.map +1 -0
- package/dist/ui-kit/primitives/button.js +8 -0
- package/dist/ui-kit/primitives/button.js.map +1 -0
- package/dist/ui-kit/primitives/card.d.ts +40 -0
- package/dist/ui-kit/primitives/card.d.ts.map +1 -0
- package/dist/ui-kit/primitives/card.js +8 -0
- package/dist/ui-kit/primitives/card.js.map +1 -0
- package/dist/ui-kit/primitives/index.d.ts +12 -2
- package/dist/ui-kit/primitives/index.d.ts.map +1 -1
- package/dist/ui-kit/primitives/index.js +12 -2
- package/dist/ui-kit/primitives/index.js.map +1 -1
- package/dist/ui-kit/primitives/layout.d.ts +12 -0
- package/dist/ui-kit/primitives/layout.d.ts.map +1 -1
- package/dist/ui-kit/primitives/layout.js +20 -2
- package/dist/ui-kit/primitives/layout.js.map +1 -1
- package/dist/ui-kit/primitives/links.d.ts +28 -2
- package/dist/ui-kit/primitives/links.d.ts.map +1 -1
- package/dist/ui-kit/primitives/links.js +11 -6
- package/dist/ui-kit/primitives/links.js.map +1 -1
- package/dist/ui-kit/primitives/lists.d.ts +43 -0
- package/dist/ui-kit/primitives/lists.d.ts.map +1 -0
- package/dist/ui-kit/primitives/lists.js +34 -0
- package/dist/ui-kit/primitives/lists.js.map +1 -0
- package/dist/ui-kit/primitives/media-frame.d.ts +28 -0
- package/dist/ui-kit/primitives/media-frame.d.ts.map +1 -0
- package/dist/ui-kit/primitives/media-frame.js +58 -0
- package/dist/ui-kit/primitives/media-frame.js.map +1 -0
- package/dist/ui-kit/primitives/media.d.ts +38 -0
- package/dist/ui-kit/primitives/media.d.ts.map +1 -0
- package/dist/ui-kit/primitives/media.js +9 -0
- package/dist/ui-kit/primitives/media.js.map +1 -0
- package/dist/ui-kit/primitives/quote-button.d.ts +4 -1
- package/dist/ui-kit/primitives/quote-button.d.ts.map +1 -1
- package/dist/ui-kit/primitives/quote-button.js +3 -2
- package/dist/ui-kit/primitives/quote-button.js.map +1 -1
- package/dist/ui-kit/primitives/stat.d.ts +25 -0
- package/dist/ui-kit/primitives/stat.d.ts.map +1 -0
- package/dist/ui-kit/primitives/stat.js +7 -0
- package/dist/ui-kit/primitives/stat.js.map +1 -0
- package/dist/ui-kit/repeated-slots.d.ts +121 -0
- package/dist/ui-kit/repeated-slots.d.ts.map +1 -0
- package/dist/ui-kit/repeated-slots.js +81 -0
- package/dist/ui-kit/repeated-slots.js.map +1 -0
- package/dist/ui-kit/sections/accordion.d.ts +4 -1
- package/dist/ui-kit/sections/accordion.d.ts.map +1 -1
- package/dist/ui-kit/sections/accordion.js +2 -2
- package/dist/ui-kit/sections/accordion.js.map +1 -1
- package/dist/ui-kit/sections/contact-block.d.ts +4 -1
- package/dist/ui-kit/sections/contact-block.d.ts.map +1 -1
- package/dist/ui-kit/sections/contact-block.js +3 -3
- package/dist/ui-kit/sections/contact-block.js.map +1 -1
- package/dist/ui-kit/sections/faqs.d.ts +4 -1
- package/dist/ui-kit/sections/faqs.d.ts.map +1 -1
- package/dist/ui-kit/sections/faqs.js +4 -5
- package/dist/ui-kit/sections/faqs.js.map +1 -1
- package/dist/ui-kit/sections/hero.d.ts +113 -0
- package/dist/ui-kit/sections/hero.d.ts.map +1 -0
- package/dist/ui-kit/sections/hero.js +58 -0
- package/dist/ui-kit/sections/hero.js.map +1 -0
- package/dist/ui-kit/sections/index.d.ts +2 -0
- package/dist/ui-kit/sections/index.d.ts.map +1 -1
- package/dist/ui-kit/sections/index.js +2 -0
- package/dist/ui-kit/sections/index.js.map +1 -1
- package/dist/ui-kit/sections/price-guide.d.ts +4 -1
- package/dist/ui-kit/sections/price-guide.d.ts.map +1 -1
- package/dist/ui-kit/sections/price-guide.js +3 -3
- package/dist/ui-kit/sections/price-guide.js.map +1 -1
- package/dist/ui-kit/sections/price-table.d.ts +7 -9
- package/dist/ui-kit/sections/price-table.d.ts.map +1 -1
- package/dist/ui-kit/sections/price-table.js +8 -8
- package/dist/ui-kit/sections/price-table.js.map +1 -1
- package/dist/ui-kit/sections/proof-strip.d.ts +4 -1
- package/dist/ui-kit/sections/proof-strip.d.ts.map +1 -1
- package/dist/ui-kit/sections/proof-strip.js +2 -2
- package/dist/ui-kit/sections/proof-strip.js.map +1 -1
- package/dist/ui-kit/sections/reviews-band.d.ts +5 -2
- package/dist/ui-kit/sections/reviews-band.d.ts.map +1 -1
- package/dist/ui-kit/sections/reviews-band.js +2 -2
- package/dist/ui-kit/sections/reviews-band.js.map +1 -1
- package/dist/ui-kit/sections/services-grid.d.ts +82 -0
- package/dist/ui-kit/sections/services-grid.d.ts.map +1 -0
- package/dist/ui-kit/sections/services-grid.js +90 -0
- package/dist/ui-kit/sections/services-grid.js.map +1 -0
- package/dist/ui-kit/sections/site-footer.d.ts +4 -1
- package/dist/ui-kit/sections/site-footer.d.ts.map +1 -1
- package/dist/ui-kit/sections/site-footer.js +9 -6
- package/dist/ui-kit/sections/site-footer.js.map +1 -1
- package/dist/ui-kit/shell/current-link.d.ts +15 -1
- package/dist/ui-kit/shell/current-link.d.ts.map +1 -1
- package/dist/ui-kit/shell/current-link.js +10 -1
- package/dist/ui-kit/shell/current-link.js.map +1 -1
- package/dist/ui-kit/shell/index.d.ts +1 -0
- package/dist/ui-kit/shell/index.d.ts.map +1 -1
- package/dist/ui-kit/shell/index.js +1 -0
- package/dist/ui-kit/shell/index.js.map +1 -1
- package/dist/ui-kit/shell/intent-prefetch.d.ts +4 -0
- package/dist/ui-kit/shell/intent-prefetch.d.ts.map +1 -0
- package/dist/ui-kit/shell/intent-prefetch.js +61 -0
- package/dist/ui-kit/shell/intent-prefetch.js.map +1 -0
- package/dist/ui-kit/shell/mobile-drawer.d.ts +7 -3
- package/dist/ui-kit/shell/mobile-drawer.d.ts.map +1 -1
- package/dist/ui-kit/shell/mobile-drawer.js +20 -4
- package/dist/ui-kit/shell/mobile-drawer.js.map +1 -1
- package/dist/ui-kit/shell/site-header.d.ts +4 -1
- package/dist/ui-kit/shell/site-header.d.ts.map +1 -1
- package/dist/ui-kit/shell/site-header.js +9 -10
- package/dist/ui-kit/shell/site-header.js.map +1 -1
- package/dist/ui-kit/shell/social-links.d.ts +1 -2
- package/dist/ui-kit/shell/social-links.d.ts.map +1 -1
- package/dist/ui-kit/shell/social-links.js +6 -3
- package/dist/ui-kit/shell/social-links.js.map +1 -1
- package/dist/ui-kit/shell/utility-bar.d.ts +4 -1
- package/dist/ui-kit/shell/utility-bar.d.ts.map +1 -1
- package/dist/ui-kit/shell/utility-bar.js +2 -2
- package/dist/ui-kit/shell/utility-bar.js.map +1 -1
- package/dist/ui-kit/skin-index.d.ts +2 -1
- package/dist/ui-kit/skin-index.d.ts.map +1 -1
- package/dist/ui-kit/skin-index.js +2 -1
- package/dist/ui-kit/skin-index.js.map +1 -1
- package/dist/ui-kit/skin.d.ts +21 -4
- package/dist/ui-kit/skin.d.ts.map +1 -1
- package/dist/ui-kit/skin.js +14 -1
- package/dist/ui-kit/skin.js.map +1 -1
- package/dist/ui-kit/structure.css +383 -3
- package/package.json +10 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next-config.d.ts","sourceRoot":"","sources":["../src/next-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AACnG,OAAO,EAGL,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAClB,MAAM,kCAAkC,CAAA;AACzC,OAAO,
|
|
1
|
+
{"version":3,"file":"next-config.d.ts","sourceRoot":"","sources":["../src/next-config.ts"],"names":[],"mappings":"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"}
|
package/dist/next-config.js
CHANGED
|
@@ -2,7 +2,11 @@ import { readdirSync, statSync } from 'node:fs';
|
|
|
2
2
|
import { join, posix } from 'node:path';
|
|
3
3
|
import { defineRedirects } from '@brandlab-digital/site-core/redirects';
|
|
4
4
|
import { assertBrandlabAliasHosts, resolveBrandlabDeployment, } from '@brandlab-digital/site-core/site';
|
|
5
|
-
import { buildBrandlabHeaderRules, parseBrandlabStaticAssetCache, } from './headers.js';
|
|
5
|
+
import { BRANDLAB_STATIC_ASSET_CACHE_CONTROL, buildBrandlabHeaderRules, parseBrandlabStaticAssetCache, } from './headers.js';
|
|
6
|
+
import { defineSiteIcons, ICON_SPRITE_ENV } from './ui-kit/icon-glyphs.js';
|
|
7
|
+
import { writeIconSprite } from './ui-kit/icon-sprite.js';
|
|
8
|
+
/** The sprite's cache rule: content-hashed names only, so a stale name never reaches a page. */
|
|
9
|
+
export const BRANDLAB_ICON_SPRITE_SOURCE = '/_bl/:file(icons\\.[0-9a-f]+\\.svg)';
|
|
6
10
|
/** Sharp's Linux binaries must travel with the contact route's image sanitiser. */
|
|
7
11
|
export const BRANDLAB_CONTACT_OUTPUT_FILE_TRACING = Object.freeze({
|
|
8
12
|
'/api/contact': Object.freeze([
|
|
@@ -23,6 +27,7 @@ const OPTION_KEYS = new Set([
|
|
|
23
27
|
'extraHeaders',
|
|
24
28
|
'staticAssetCache',
|
|
25
29
|
'mdx',
|
|
30
|
+
'icons',
|
|
26
31
|
'environment',
|
|
27
32
|
'projectRoot',
|
|
28
33
|
]);
|
|
@@ -241,6 +246,16 @@ function assertStaticAssetFolders(folders, root) {
|
|
|
241
246
|
}
|
|
242
247
|
}
|
|
243
248
|
}
|
|
249
|
+
/** A site icon set, checked again here: the config may be handed an object that never went through defineSiteIcons. */
|
|
250
|
+
function siteIconSet(site) {
|
|
251
|
+
if (site === undefined)
|
|
252
|
+
return undefined;
|
|
253
|
+
const set = site;
|
|
254
|
+
if (!set || typeof set !== 'object' || !Array.isArray(set.names) || !set.glyphs || typeof set.glyphs !== 'object') {
|
|
255
|
+
throw new Error('icons.site must come from defineSiteIcons.');
|
|
256
|
+
}
|
|
257
|
+
return defineSiteIcons(Object.fromEntries(set.names.map((name) => [name, set.glyphs[name]])));
|
|
258
|
+
}
|
|
244
259
|
/**
|
|
245
260
|
* Converts the redirect table to Next redirects: each entry keeps its 301 or
|
|
246
261
|
* 308 status (Next forwards the query string), gains a single-hop
|
|
@@ -315,6 +330,22 @@ export function defineBrandlabNextConfig(options) {
|
|
|
315
330
|
...(options.extraHeaders ? { extraHeaders: options.extraHeaders } : {}),
|
|
316
331
|
...(options.staticAssetCache ? { staticAssetCache: options.staticAssetCache } : {}),
|
|
317
332
|
});
|
|
333
|
+
if (options.icons !== undefined) {
|
|
334
|
+
if (!options.icons || typeof options.icons !== 'object' || Array.isArray(options.icons)) {
|
|
335
|
+
throw new Error('icons must be { site?: defineSiteIcons(...) } ({} for the library icons only).');
|
|
336
|
+
}
|
|
337
|
+
assertKnownKeys(options.icons, new Set(['site']), 'icons');
|
|
338
|
+
}
|
|
339
|
+
const sprite = options.icons === undefined ? undefined : writeIconSprite(options.projectRoot ?? process.cwd(), siteIconSet(options.icons.site));
|
|
340
|
+
// The same production-only rule as staticAssetCache: Previews keep private, no-store.
|
|
341
|
+
if (sprite && deployment.productionBuild && deployment.environment !== 'preview') {
|
|
342
|
+
// After the static folders, before the non-canonical host rule.
|
|
343
|
+
const at = headerRules.findIndex((rule) => rule.missing !== undefined);
|
|
344
|
+
headerRules.splice(at === -1 ? headerRules.length : at, 0, {
|
|
345
|
+
source: BRANDLAB_ICON_SPRITE_SOURCE,
|
|
346
|
+
headers: [{ key: 'Cache-Control', value: BRANDLAB_STATIC_ASSET_CACHE_CONTROL }],
|
|
347
|
+
});
|
|
348
|
+
}
|
|
318
349
|
const redirects = buildBrandlabRedirects({
|
|
319
350
|
site: options.site,
|
|
320
351
|
redirects: options.redirects,
|
|
@@ -323,7 +354,10 @@ export function defineBrandlabNextConfig(options) {
|
|
|
323
354
|
const config = {
|
|
324
355
|
poweredByHeader: false,
|
|
325
356
|
skipTrailingSlashRedirect: true,
|
|
326
|
-
env: {
|
|
357
|
+
env: {
|
|
358
|
+
NEXT_PUBLIC_VERCEL_ENV: deployment.environment,
|
|
359
|
+
...(sprite ? { [ICON_SPRITE_ENV]: sprite.href } : {}),
|
|
360
|
+
},
|
|
327
361
|
outputFileTracingIncludes: Object.fromEntries(Object.entries(BRANDLAB_CONTACT_OUTPUT_FILE_TRACING).map(([route, globs]) => [route, [...globs]])),
|
|
328
362
|
// A Vercel build (preview or production) is checked like any production build, whatever NODE_ENV says.
|
|
329
363
|
images: buildImagesConfig(options.images, deployment.productionBuild || deployment.environment !== 'development'),
|
package/dist/next-config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next-config.js","sourceRoot":"","sources":["../src/next-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, statSync } from 'node:fs'\nimport { join, posix } from 'node:path'\nimport { defineRedirects, type BrandlabRedirectTable } from '@brandlab-digital/site-core/redirects'\nimport {\n assertBrandlabAliasHosts,\n resolveBrandlabDeployment,\n type BrandlabDeploymentEnvironment,\n type BrandlabEnvironment,\n type BrandlabSite,\n} from '@brandlab-digital/site-core/site'\nimport {\n buildBrandlabHeaderRules,\n parseBrandlabStaticAssetCache,\n type BrandlabContentSecurityPolicyExtensions,\n type BrandlabHeader,\n type BrandlabHeaderRule,\n type BrandlabHstsExpansion,\n type BrandlabStaticAssetFolder,\n} from './headers.js'\n\n/** Next redirect records: 308 stays `permanent: true`, 301 stays `statusCode: 301`. */\nexport type BrandlabNextRedirect = {\n source: string\n destination: string\n has?: { type: 'host'; value: string }[]\n} & ({ permanent: true; statusCode?: never } | { statusCode: 301; permanent?: never })\n\nexport interface BrandlabNextRemotePattern {\n protocol?: 'http' | 'https'\n hostname: string\n port?: string\n pathname?: string\n search?: string\n}\n\n/** The site's own image settings; the output format is always WebP. */\nexport interface BrandlabNextImagesOptions {\n deviceSizes?: readonly number[]\n imageSizes?: readonly number[]\n qualities?: readonly number[]\n minimumCacheTTL?: number\n /**\n * Remote image sources the optimiser may fetch. From 3.3.3 a production build\n * (`next build`, `next start`) refuses an `http` pattern, a pattern without an\n * explicit `https` protocol and a local or private-network host such as `localhost`.\n */\n remotePatterns?: readonly BrandlabNextRemotePattern[]\n /**\n * Sources for `next dev` only, such as `{ protocol: 'http', hostname: 'localhost' }`\n * (3.3.3). They are added to remotePatterns when the build is not a production\n * build and never reach a deployment.\n */\n developmentRemotePatterns?: readonly BrandlabNextRemotePattern[]\n}\n\nexport interface BrandlabNextImagesConfig {\n formats: 'image/webp'[]\n deviceSizes?: number[]\n imageSizes?: number[]\n qualities?: number[]\n minimumCacheTTL?: number\n remotePatterns?: BrandlabNextRemotePattern[]\n}\n\nexport interface BrandlabNextConfig {\n poweredByHeader: false\n /** Trailing slashes are handled by single-hop redirect rules instead. */\n skipTrailingSlashRedirect: true\n env: { NEXT_PUBLIC_VERCEL_ENV: BrandlabDeploymentEnvironment }\n outputFileTracingIncludes: Record<string, string[]>\n images: BrandlabNextImagesConfig\n pageExtensions?: string[]\n headers: () => Promise<BrandlabHeaderRule[]>\n redirects: () => Promise<BrandlabNextRedirect[]>\n}\n\nexport interface BrandlabNextConfigOptions {\n site: BrandlabSite\n /**\n * Hosts that permanently redirect every path to the canonical origin (the\n * `www` host, a Vercel project host, a retired domain). Declared here rather\n * than in the site identity, which client components import, so the list\n * never reaches a browser bundle. Their rules follow any `site.aliasHosts`\n * rules, in order, as the last redirects.\n */\n aliasHosts?: readonly string[]\n /** The src/data/redirects.ts table (defineRedirects). */\n redirects: BrandlabRedirectTable\n images: BrandlabNextImagesOptions\n /** Reviewed CSP origins for declared integrations such as Meta Pixel or map embeds. */\n csp?: BrandlabContentSecurityPolicyExtensions\n hsts?: BrandlabHstsExpansion\n /** Reviewed exception to the default Permissions-Policy that is already live. */\n permissionsPolicy?: string\n /** Reviewed response headers that are already live; protected headers cannot be replaced. */\n extraHeaders?: readonly BrandlabHeader[]\n /**\n * Public folders of static files that never change in place, written as Next\n * sources such as `['/images/:path*', '/fonts/:path*']`. Production builds serve\n * their files (names with an extension) with `public, max-age=31536000, immutable`;\n * Previews keep `private, no-store`. Each folder must exist under `public/`, and\n * no route under `src/app` or `app` may answer below it.\n */\n staticAssetCache?: readonly string[]\n /** Defaults to process.env; tests supply a fixed environment. */\n environment?: BrandlabEnvironment\n /** The project root for the staticAssetCache checks; defaults to process.cwd(). */\n projectRoot?: string\n}\n\n/** Sharp's Linux binaries must travel with the contact route's image sanitiser. */\nexport const BRANDLAB_CONTACT_OUTPUT_FILE_TRACING = Object.freeze({\n '/api/contact': Object.freeze([\n 'node_modules/sharp/**/*',\n 'node_modules/@img/sharp-linux-x64/**/*',\n 'node_modules/@img/sharp-libvips-linux-x64/**/*',\n ]),\n})\n\nconst MDX_PAGE_EXTENSIONS = ['tsx', 'ts', 'jsx', 'js', 'mdx', 'md']\nconst OPTION_KEYS = new Set([\n 'site',\n 'aliasHosts',\n 'redirects',\n 'images',\n 'csp',\n 'hsts',\n 'permissionsPolicy',\n 'extraHeaders',\n 'staticAssetCache',\n 'mdx',\n 'environment',\n 'projectRoot',\n])\nconst IMAGE_KEYS = new Set(['deviceSizes', 'imageSizes', 'qualities', 'minimumCacheTTL', 'remotePatterns', 'developmentRemotePatterns'])\nconst REMOTE_PATTERN_KEYS = new Set(['protocol', 'hostname', 'port', 'pathname', 'search'])\n\nfunction assertKnownKeys(value: object, allowed: ReadonlySet<string>, field: string, hint = '') {\n const unsupported = Object.keys(value).filter((key) => !allowed.has(key))\n if (unsupported.length > 0) {\n throw new Error(`${field} contains unsupported keys: ${unsupported.join(', ')}.${hint}`)\n }\n}\n\nfunction positiveIntegers(values: readonly number[] | undefined, field: string) {\n if (values === undefined) return undefined\n if (\n !Array.isArray(values) ||\n values.length === 0 ||\n values.some((value) => !Number.isSafeInteger(value) || value < 1)\n ) {\n throw new Error(`images.${field} must list positive integers.`)\n }\n return [...values]\n}\n\n/**\n * A host no deployment should fetch images from: loopback (`localhost`, `*.localhost`,\n * 127.0.0.0/8, ::1), unspecified (0.0.0.0, ::), private (10/8, 172.16/12, 192.168/16,\n * fc00::/7), shared (100.64/10) or link-local (169.254/16, fe80::/10), in any spelling a URL\n * reads as one of them, or a wildcard host that admits one (`**`, `10.*.*.*`).\n */\nfunction isLocalImageHost(hostname: string): boolean {\n const host = hostname.trim().toLowerCase().replace(/^\\[(.*)\\]$/, '$1').replace(/\\.$/, '')\n // Other picomatch syntax (?, braces, classes, extglobs) cannot be judged here, so it is refused.\n if (/[?{}[\\]()!@+]/.test(host)) return true\n // A wildcard host is local when it admits a local address: Next matches hostnames with picomatch, whose `*` stops\n // only at a slash, so `*` and `**` both admit `localhost`, and `10.*.*.*` admits 10.0.0.1. Any wildcard address\n // (`192.168.1.*`, `fd12:*`) counts as local.\n if (host.includes('*')) {\n if (/^[\\d.*]+$/.test(host) || host.includes(':')) return true\n const source = host.split(/(\\*\\*|\\*)/).map((part) => (part === '**' ? '.*' : part === '*' ? '[^/]*' : part.replace(/[.+?^$()|{}[\\]\\\\]/g, '\\\\$&'))).join('')\n const glob = new RegExp('^' + source + '$')\n return LOCAL_HOST_SAMPLES.some((sample) => glob.test(sample))\n }\n // The address a URL reads it as: 127.1, 0x7f.0.0.1 and [::ffff:127.0.0.1] all name 127.0.0.1.\n let named = host\n try {\n named = new URL('https://' + (host.includes(':') ? '[' + host + ']' : host)).hostname.replace(/^\\[(.*)\\]$/, '$1')\n } catch {\n // not a host a URL can name: judged as written\n }\n if (named === 'localhost' || named.endsWith('.localhost')) return true\n const hex = named.match(/^(?:0{0,4}:){0,5}:?ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/)\n const dotted = hex ? [parseInt(hex[1]!, 16) >> 8, parseInt(hex[1]!, 16) & 255, parseInt(hex[2]!, 16) >> 8, parseInt(hex[2]!, 16) & 255].join('.') : undefined\n const mapped = named.match(/^(?:0{0,4}:){0,5}:?ffff:(\\d{1,3}(?:\\.\\d{1,3}){3})$/)\n const ipv4 = (dotted ?? mapped?.[1] ?? named).match(/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/)\n if (ipv4) {\n const [a, b] = [Number(ipv4[1]), Number(ipv4[2])]\n return a === 0 || a === 10 || a === 127 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) ||\n (a === 192 && b === 168) || (a === 100 && b >= 64 && b <= 127)\n }\n if (!named.includes(':')) return false\n const groups = named.split(':')\n const allZero = (parts: string[]) => parts.every((part) => /^0*$/.test(part))\n // :: and ::1 in any spelling (0:0:0:0:0:0:0:1), then the private and link-local prefixes.\n if (allZero(groups) || (allZero(groups.slice(0, -1)) && /^0*1$/.test(groups.at(-1) ?? ''))) return true\n return /^f[cd][0-9a-f]{0,2}:/.test(named) || /^fe[89ab][0-9a-f]?:/.test(named)\n}\n\n/** One address in each local range, to judge a wildcard host by. */\nconst LOCAL_HOST_SAMPLES = ['localhost', 'a.localhost', '0.0.0.0', '10.0.0.1', '100.64.0.1', '127.0.0.1', '169.254.169.254', '172.16.0.1', '192.168.0.1', '::1', 'fc00::1', 'fe80::1']\n\nfunction describeRemotePattern(pattern: BrandlabNextRemotePattern): string {\n const path = pattern.pathname === undefined ? '/**' : pattern.pathname.startsWith('/') ? pattern.pathname : `/${pattern.pathname}`\n return `${pattern.protocol ?? 'any protocol'}://${pattern.hostname}${pattern.port ? `:${pattern.port}` : ''}${path}`\n}\n\n/** A validated copy of a remote pattern list: the keys and value types Next reads. */\nfunction remotePatternList(value: unknown, field: string): BrandlabNextRemotePattern[] | undefined {\n if (value === undefined) return undefined\n if (!Array.isArray(value)) throw new Error(`images.${field} must be an array.`)\n return value.map((pattern: unknown, index) => {\n const at = `images.${field}[${index}]`\n if (!pattern || typeof pattern !== 'object' || Array.isArray(pattern)) {\n throw new Error(`${at} must be a { protocol, hostname, port?, pathname?, search? } pattern.`)\n }\n assertKnownKeys(pattern, REMOTE_PATTERN_KEYS, at)\n const record = pattern as Record<string, unknown>\n if (typeof record.hostname !== 'string' || !record.hostname.trim()) throw new Error(`${at}.hostname must name a host.`)\n if (record.protocol !== undefined && record.protocol !== 'https' && record.protocol !== 'http') {\n throw new Error(`${at}.protocol must be 'https' ('http' only in images.developmentRemotePatterns).`)\n }\n for (const key of ['port', 'pathname', 'search'] as const) {\n if (record[key] !== undefined && typeof record[key] !== 'string') throw new Error(`${at}.${key} must be a string.`)\n }\n return { ...(pattern as BrandlabNextRemotePattern) }\n })\n}\n\n/**\n * A production build fetches remote images only over https from a public host:\n * the optimiser fetches a remote pattern's images on any visitor's request\n * (GHSA-cjq9-62q9-8jv4), and an http or local source is a development convenience.\n */\nfunction assertProductionRemotePatterns(patterns: readonly BrandlabNextRemotePattern[]) {\n patterns.forEach((pattern, index) => {\n const problems = [\n ...(pattern.protocol === 'https' ? [] : [pattern.protocol === 'http' ? 'uses http' : \"does not name protocol 'https'\"]),\n ...(isLocalImageHost(pattern.hostname)\n ? [/[*?{}[\\]()!@+]/.test(pattern.hostname) ? `admits local addresses (${pattern.hostname} can match localhost or a private address)` : `names the local address ${pattern.hostname}`]\n : []),\n ]\n if (problems.length === 0) return\n throw new Error(\n `images.remotePatterns[${index}] (${describeRemotePattern(pattern)}) ${problems.join(' and ')}. ` +\n 'A production build only fetches remote images over https from a public host. Remove the pattern, ' +\n 'or move a development-only source to images.developmentRemotePatterns, which only next dev uses.',\n )\n })\n}\n\nfunction buildImagesConfig(images: BrandlabNextImagesOptions, productionBuild: boolean): BrandlabNextImagesConfig {\n if (!images || typeof images !== 'object' || Array.isArray(images)) {\n throw new Error('images must declare the site image settings ({} for Next defaults).')\n }\n assertKnownKeys(images, IMAGE_KEYS, 'images', ' The output format is always image/webp.')\n const deviceSizes = positiveIntegers(images.deviceSizes, 'deviceSizes')\n const imageSizes = positiveIntegers(images.imageSizes, 'imageSizes')\n const qualities = positiveIntegers(images.qualities, 'qualities')\n if (qualities?.some((quality) => quality > 100)) {\n throw new Error('images.qualities must be between 1 and 100.')\n }\n if (\n images.minimumCacheTTL !== undefined &&\n (!Number.isSafeInteger(images.minimumCacheTTL) || images.minimumCacheTTL < 0)\n ) {\n throw new Error('images.minimumCacheTTL must be a non-negative integer of seconds.')\n }\n const remotePatterns = remotePatternList(images.remotePatterns, 'remotePatterns')\n const developmentRemotePatterns = remotePatternList(images.developmentRemotePatterns, 'developmentRemotePatterns')\n if (productionBuild && remotePatterns) assertProductionRemotePatterns(remotePatterns)\n // next dev (and tests) also fetch the development-only sources; a production build never does.\n const served = productionBuild || !developmentRemotePatterns?.length\n ? remotePatterns\n : [...(remotePatterns ?? []), ...developmentRemotePatterns]\n return {\n formats: ['image/webp'],\n ...(deviceSizes ? { deviceSizes } : {}),\n ...(imageSizes ? { imageSizes } : {}),\n ...(qualities ? { qualities } : {}),\n ...(images.minimumCacheTTL !== undefined ? { minimumCacheTTL: images.minimumCacheTTL } : {}),\n ...(served ? { remotePatterns: served } : {}),\n }\n}\n\nconst PAGE_OR_ROUTE_FILE = /^(?:page|route)\\.[A-Za-z0-9]+$/\nconst METADATA_ROUTE_FILE = /^(?:opengraph-image|twitter-image|icon|apple-icon|sitemap|robots|manifest)(?:[\\w.-]*)\\.[A-Za-z0-9]+$/\n\nfunction isDirectory(path: string) {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n\n/**\n * The first route file under an app directory that can answer a path strictly\n * below `/<folder>/`. `depth` counts the folder segments matched so far: route\n * groups, intercepts and parallel slots add none, a dynamic segment matches any\n * one, and a catch-all reaches every path below the folder.\n */\nfunction routeBelowFolder(\n directory: string,\n folder: readonly string[],\n depth: number,\n relative: string,\n): string | null {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const name = entry.name\n if (name.startsWith('_') || name.startsWith('.') || name === 'node_modules') continue\n const path = join(directory, name)\n const nextRelative = posix.join(relative, name)\n if (entry.isFile()) {\n // Page and route files serve their own directory; metadata files serve a path below it.\n const below = depth > folder.length && PAGE_OR_ROUTE_FILE.test(name)\n const metadata = depth >= folder.length && METADATA_ROUTE_FILE.test(name)\n if (below || metadata) return nextRelative\n continue\n }\n if (!entry.isDirectory()) continue\n let next: number | null = null\n if (name.startsWith('(') || name.startsWith('@')) next = depth\n else if (/^\\[\\[?\\.\\.\\./.test(name)) next = folder.length + 1\n else if (depth >= folder.length || name.startsWith('[') || name === folder[depth]) next = depth + 1\n if (next === null) continue\n const found = routeBelowFolder(path, folder, next, nextRelative)\n if (found) return found\n }\n return null\n}\n\n/** Each declared folder exists under public/ and no app route answers below it. */\nfunction assertStaticAssetFolders(folders: readonly BrandlabStaticAssetFolder[], root: string) {\n for (const { source, folder } of folders) {\n const publicFolder = posix.join('public', ...folder)\n if (!isDirectory(join(root, publicFolder))) {\n throw new Error(`staticAssetCache \"${source}\": ${publicFolder} is not a folder of static files in ${root}.`)\n }\n for (const appDirectory of ['src/app', 'app']) {\n if (!isDirectory(join(root, appDirectory))) continue\n const route = routeBelowFolder(join(root, appDirectory), folder, 0, appDirectory)\n if (route) {\n throw new Error(\n `staticAssetCache \"${source}\": ${route} answers below /${folder.join('/')}, so immutable caching could reach a page or route.`,\n )\n }\n }\n }\n}\n\n/**\n * Converts the redirect table to Next redirects: each entry keeps its 301 or\n * 308 status (Next forwards the query string), gains a single-hop\n * trailing-slash variant, then one trailing-slash rule and one permanent\n * canonical-host rule per alias host follow. There is no x-forwarded-proto\n * rule: Vercel's edge already enforces HTTPS.\n */\nexport function buildBrandlabRedirects(options: {\n site: BrandlabSite\n redirects: BrandlabRedirectTable\n /** next.config's alias hosts, after the site identity's own (3.2.1). */\n aliasHosts?: readonly string[]\n}): BrandlabNextRedirect[] {\n const aliasHosts = brandlabAliasHosts(options.site, options.aliasHosts)\n const table = defineRedirects(options.redirects)\n const entries = table.flatMap((redirect): BrandlabNextRedirect[] => {\n const status = redirect.status === 301\n ? { statusCode: 301 as const }\n : { permanent: true as const }\n const has = redirect.host ? { has: [{ type: 'host' as const, value: redirect.host }] } : {}\n const record = (source: string): BrandlabNextRedirect => ({\n source,\n destination: redirect.destination,\n ...status,\n ...has,\n })\n return redirect.source === '/'\n ? [record(redirect.source)]\n : [record(redirect.source), record(`${redirect.source}/`)]\n })\n return [\n ...entries,\n { source: '/:path+/', destination: '/:path+', permanent: true },\n ...aliasHosts.map((host): BrandlabNextRedirect => ({\n source: '/:path*',\n has: [{ type: 'host', value: host }],\n destination: `${options.site.canonicalUrl}/:path*`,\n permanent: true,\n })),\n ]\n}\n\n/**\n * Every alias host: the site identity's (the 3.0–3.2.0 place) then next.config's\n * (3.2.1), validated together so a host is never declared twice.\n */\nexport function brandlabAliasHosts(site: BrandlabSite, aliasHosts: readonly string[] | undefined): readonly string[] {\n if (aliasHosts === undefined) return site.aliasHosts\n assertBrandlabAliasHosts(aliasHosts, site.canonicalHost ?? new URL(site.canonicalUrl).hostname, 'next.config aliasHosts')\n const all = [...site.aliasHosts, ...aliasHosts]\n const duplicate = all.find((host, index) => all.indexOf(host) !== index)\n if (duplicate) throw new Error(`Alias host \"${duplicate}\" is declared in both the site identity and next.config aliasHosts.`)\n return all\n}\n\n/**\n * The whole next.config.ts after its first line\n * `import '@brandlab-digital/site-next/image-runtime'`:\n * `export default defineBrandlabNextConfig({ site, redirects, images })`.\n *\n * Sets poweredByHeader: false, WebP image output, Sharp output tracing for\n * /api/contact, NEXT_PUBLIC_VERCEL_ENV for browser gates, the deployment's\n * header rules (with immutable caching for the declared static public folders on\n * production builds) and the redirect table. Validation runs when the config\n * loads, so an invalid table, header exception or static folder fails the build,\n * as does (3.3.3) a production build's http or local image remote pattern.\n */\nexport function defineBrandlabNextConfig(\n options: BrandlabNextConfigOptions & { mdx?: undefined },\n): BrandlabNextConfig\nexport function defineBrandlabNextConfig<Wrapped>(\n options: BrandlabNextConfigOptions & {\n /** The @next/mdx wrapper: createMDX({ options: { remarkPlugins: ['remark-gfm'] } }). */\n mdx: (config: BrandlabNextConfig) => Wrapped\n },\n): Wrapped\nexport function defineBrandlabNextConfig(\n options: BrandlabNextConfigOptions & { mdx?: (config: BrandlabNextConfig) => unknown },\n): unknown {\n if (!options || typeof options !== 'object') {\n throw new TypeError('defineBrandlabNextConfig requires the site, redirects and images.')\n }\n assertKnownKeys(options, OPTION_KEYS, 'next.config options')\n if (!options.site?.canonicalUrl || !Array.isArray(options.site.aliasHosts)) {\n throw new Error('site must come from defineBrandlabSite.')\n }\n if (options.mdx !== undefined && typeof options.mdx !== 'function') {\n throw new TypeError('mdx must be the @next/mdx config wrapper.')\n }\n const deployment = resolveBrandlabDeployment(options.environment ?? process.env)\n if (options.staticAssetCache !== undefined) {\n assertStaticAssetFolders(\n parseBrandlabStaticAssetCache(options.staticAssetCache),\n options.projectRoot ?? process.cwd(),\n )\n }\n const headerRules = buildBrandlabHeaderRules({\n deployment,\n canonicalHost: options.site.canonicalHost ?? new URL(options.site.canonicalUrl).hostname,\n ...(options.csp ? { contentSecurityPolicyExtensions: options.csp } : {}),\n ...(options.hsts ? { hsts: options.hsts } : {}),\n ...(options.permissionsPolicy ? { permissionsPolicy: options.permissionsPolicy } : {}),\n ...(options.extraHeaders ? { extraHeaders: options.extraHeaders } : {}),\n ...(options.staticAssetCache ? { staticAssetCache: options.staticAssetCache } : {}),\n })\n const redirects = buildBrandlabRedirects({\n site: options.site,\n redirects: options.redirects,\n ...(options.aliasHosts !== undefined ? { aliasHosts: options.aliasHosts } : {}),\n })\n\n const config: BrandlabNextConfig = {\n poweredByHeader: false,\n skipTrailingSlashRedirect: true,\n env: { NEXT_PUBLIC_VERCEL_ENV: deployment.environment },\n outputFileTracingIncludes: Object.fromEntries(\n Object.entries(BRANDLAB_CONTACT_OUTPUT_FILE_TRACING).map(([route, globs]) => [route, [...globs]]),\n ),\n // A Vercel build (preview or production) is checked like any production build, whatever NODE_ENV says.\n images: buildImagesConfig(options.images, deployment.productionBuild || deployment.environment !== 'development'),\n ...(options.mdx ? { pageExtensions: [...MDX_PAGE_EXTENSIONS] } : {}),\n headers: async () =>\n headerRules.map((rule) => ({\n source: rule.source,\n ...(rule.missing ? { missing: rule.missing.map((condition) => ({ ...condition })) } : {}),\n headers: rule.headers.map((header) => ({ ...header })),\n })),\n redirects: async () =>\n redirects.map((redirect) => ({\n ...redirect,\n ...(redirect.has ? { has: redirect.has.map((condition) => ({ ...condition })) } : {}),\n })),\n }\n return options.mdx ? options.mdx(config) : config\n}\n"]}
|
|
1
|
+
{"version":3,"file":"next-config.js","sourceRoot":"","sources":["../src/next-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, statSync } from 'node:fs'\nimport { join, posix } from 'node:path'\nimport { defineRedirects, type BrandlabRedirectTable } from '@brandlab-digital/site-core/redirects'\nimport {\n assertBrandlabAliasHosts,\n resolveBrandlabDeployment,\n type BrandlabDeploymentEnvironment,\n type BrandlabEnvironment,\n type BrandlabSite,\n} from '@brandlab-digital/site-core/site'\nimport {\n BRANDLAB_STATIC_ASSET_CACHE_CONTROL,\n buildBrandlabHeaderRules,\n parseBrandlabStaticAssetCache,\n type BrandlabContentSecurityPolicyExtensions,\n type BrandlabHeader,\n type BrandlabHeaderRule,\n type BrandlabHstsExpansion,\n type BrandlabStaticAssetFolder,\n} from './headers.js'\nimport { defineSiteIcons, ICON_SPRITE_ENV, type SiteIconSet } from './ui-kit/icon-glyphs.js'\nimport { writeIconSprite } from './ui-kit/icon-sprite.js'\n\n/** Next redirect records: 308 stays `permanent: true`, 301 stays `statusCode: 301`. */\nexport type BrandlabNextRedirect = {\n source: string\n destination: string\n has?: { type: 'host'; value: string }[]\n} & ({ permanent: true; statusCode?: never } | { statusCode: 301; permanent?: never })\n\nexport interface BrandlabNextRemotePattern {\n protocol?: 'http' | 'https'\n hostname: string\n port?: string\n pathname?: string\n search?: string\n}\n\n/** The site's own image settings; the output format is always WebP. */\nexport interface BrandlabNextImagesOptions {\n deviceSizes?: readonly number[]\n imageSizes?: readonly number[]\n qualities?: readonly number[]\n minimumCacheTTL?: number\n /**\n * Remote image sources the optimiser may fetch. From 3.3.3 a production build\n * (`next build`, `next start`) refuses an `http` pattern, a pattern without an\n * explicit `https` protocol and a local or private-network host such as `localhost`.\n */\n remotePatterns?: readonly BrandlabNextRemotePattern[]\n /**\n * Sources for `next dev` only, such as `{ protocol: 'http', hostname: 'localhost' }`\n * (3.3.3). They are added to remotePatterns when the build is not a production\n * build and never reach a deployment.\n */\n developmentRemotePatterns?: readonly BrandlabNextRemotePattern[]\n}\n\nexport interface BrandlabNextImagesConfig {\n formats: 'image/webp'[]\n deviceSizes?: number[]\n imageSizes?: number[]\n qualities?: number[]\n minimumCacheTTL?: number\n remotePatterns?: BrandlabNextRemotePattern[]\n}\n\nexport interface BrandlabNextConfig {\n poweredByHeader: false\n /** Trailing slashes are handled by single-hop redirect rules instead. */\n skipTrailingSlashRedirect: true\n env: {\n NEXT_PUBLIC_VERCEL_ENV: BrandlabDeploymentEnvironment\n /** The icon sprite's path (3.14.0), set when `icons` is declared. */\n NEXT_PUBLIC_BL_ICON_SPRITE?: string\n }\n outputFileTracingIncludes: Record<string, string[]>\n images: BrandlabNextImagesConfig\n pageExtensions?: string[]\n headers: () => Promise<BrandlabHeaderRule[]>\n redirects: () => Promise<BrandlabNextRedirect[]>\n}\n\nexport interface BrandlabNextConfigOptions {\n site: BrandlabSite\n /**\n * Hosts that permanently redirect every path to the canonical origin (the\n * `www` host, a Vercel project host, a retired domain). Declared here rather\n * than in the site identity, which client components import, so the list\n * never reaches a browser bundle. Their rules follow any `site.aliasHosts`\n * rules, in order, as the last redirects.\n */\n aliasHosts?: readonly string[]\n /** The src/data/redirects.ts table (defineRedirects). */\n redirects: BrandlabRedirectTable\n images: BrandlabNextImagesOptions\n /** Reviewed CSP origins for declared integrations such as Meta Pixel or map embeds. */\n csp?: BrandlabContentSecurityPolicyExtensions\n hsts?: BrandlabHstsExpansion\n /** Reviewed exception to the default Permissions-Policy that is already live. */\n permissionsPolicy?: string\n /** Reviewed response headers that are already live; protected headers cannot be replaced. */\n extraHeaders?: readonly BrandlabHeader[]\n /**\n * Public folders of static files that never change in place, written as Next\n * sources such as `['/images/:path*', '/fonts/:path*']`. Production builds serve\n * their files (names with an extension) with `public, max-age=31536000, immutable`;\n * Previews keep `private, no-store`. Each folder must exist under `public/`, and\n * no route under `src/app` or `app` may answer below it.\n */\n staticAssetCache?: readonly string[]\n /**\n * The ui-kit icon sprite (3.14.0). When declared, loading the config writes `public/_bl/icons.<hash>.svg` (every\n * library icon plus `site`, the set from `defineSiteIcons`), removes older sprites there and sets\n * `NEXT_PUBLIC_BL_ICON_SPRITE`, so every `Icon` renders a `<use>` into the sprite instead of an inline glyph.\n * Production builds serve the file with `public, max-age=31536000, immutable`. Add `public/_bl/` to `.gitignore`.\n */\n icons?: BrandlabIconsOptions\n /** Defaults to process.env; tests supply a fixed environment. */\n environment?: BrandlabEnvironment\n /** The project root for the staticAssetCache checks and the icon sprite; defaults to process.cwd(). */\n projectRoot?: string\n}\n\nexport interface BrandlabIconsOptions {\n /** The site's own icons, from `defineSiteIcons` (`src/site/icons.ts`). */\n site?: SiteIconSet\n}\n\n/** The sprite's cache rule: content-hashed names only, so a stale name never reaches a page. */\nexport const BRANDLAB_ICON_SPRITE_SOURCE = '/_bl/:file(icons\\\\.[0-9a-f]+\\\\.svg)'\n\n/** Sharp's Linux binaries must travel with the contact route's image sanitiser. */\nexport const BRANDLAB_CONTACT_OUTPUT_FILE_TRACING = Object.freeze({\n '/api/contact': Object.freeze([\n 'node_modules/sharp/**/*',\n 'node_modules/@img/sharp-linux-x64/**/*',\n 'node_modules/@img/sharp-libvips-linux-x64/**/*',\n ]),\n})\n\nconst MDX_PAGE_EXTENSIONS = ['tsx', 'ts', 'jsx', 'js', 'mdx', 'md']\nconst OPTION_KEYS = new Set([\n 'site',\n 'aliasHosts',\n 'redirects',\n 'images',\n 'csp',\n 'hsts',\n 'permissionsPolicy',\n 'extraHeaders',\n 'staticAssetCache',\n 'mdx',\n 'icons',\n 'environment',\n 'projectRoot',\n])\nconst IMAGE_KEYS = new Set(['deviceSizes', 'imageSizes', 'qualities', 'minimumCacheTTL', 'remotePatterns', 'developmentRemotePatterns'])\nconst REMOTE_PATTERN_KEYS = new Set(['protocol', 'hostname', 'port', 'pathname', 'search'])\n\nfunction assertKnownKeys(value: object, allowed: ReadonlySet<string>, field: string, hint = '') {\n const unsupported = Object.keys(value).filter((key) => !allowed.has(key))\n if (unsupported.length > 0) {\n throw new Error(`${field} contains unsupported keys: ${unsupported.join(', ')}.${hint}`)\n }\n}\n\nfunction positiveIntegers(values: readonly number[] | undefined, field: string) {\n if (values === undefined) return undefined\n if (\n !Array.isArray(values) ||\n values.length === 0 ||\n values.some((value) => !Number.isSafeInteger(value) || value < 1)\n ) {\n throw new Error(`images.${field} must list positive integers.`)\n }\n return [...values]\n}\n\n/**\n * A host no deployment should fetch images from: loopback (`localhost`, `*.localhost`,\n * 127.0.0.0/8, ::1), unspecified (0.0.0.0, ::), private (10/8, 172.16/12, 192.168/16,\n * fc00::/7), shared (100.64/10) or link-local (169.254/16, fe80::/10), in any spelling a URL\n * reads as one of them, or a wildcard host that admits one (`**`, `10.*.*.*`).\n */\nfunction isLocalImageHost(hostname: string): boolean {\n const host = hostname.trim().toLowerCase().replace(/^\\[(.*)\\]$/, '$1').replace(/\\.$/, '')\n // Other picomatch syntax (?, braces, classes, extglobs) cannot be judged here, so it is refused.\n if (/[?{}[\\]()!@+]/.test(host)) return true\n // A wildcard host is local when it admits a local address: Next matches hostnames with picomatch, whose `*` stops\n // only at a slash, so `*` and `**` both admit `localhost`, and `10.*.*.*` admits 10.0.0.1. Any wildcard address\n // (`192.168.1.*`, `fd12:*`) counts as local.\n if (host.includes('*')) {\n if (/^[\\d.*]+$/.test(host) || host.includes(':')) return true\n const source = host.split(/(\\*\\*|\\*)/).map((part) => (part === '**' ? '.*' : part === '*' ? '[^/]*' : part.replace(/[.+?^$()|{}[\\]\\\\]/g, '\\\\$&'))).join('')\n const glob = new RegExp('^' + source + '$')\n return LOCAL_HOST_SAMPLES.some((sample) => glob.test(sample))\n }\n // The address a URL reads it as: 127.1, 0x7f.0.0.1 and [::ffff:127.0.0.1] all name 127.0.0.1.\n let named = host\n try {\n named = new URL('https://' + (host.includes(':') ? '[' + host + ']' : host)).hostname.replace(/^\\[(.*)\\]$/, '$1')\n } catch {\n // not a host a URL can name: judged as written\n }\n if (named === 'localhost' || named.endsWith('.localhost')) return true\n const hex = named.match(/^(?:0{0,4}:){0,5}:?ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/)\n const dotted = hex ? [parseInt(hex[1]!, 16) >> 8, parseInt(hex[1]!, 16) & 255, parseInt(hex[2]!, 16) >> 8, parseInt(hex[2]!, 16) & 255].join('.') : undefined\n const mapped = named.match(/^(?:0{0,4}:){0,5}:?ffff:(\\d{1,3}(?:\\.\\d{1,3}){3})$/)\n const ipv4 = (dotted ?? mapped?.[1] ?? named).match(/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/)\n if (ipv4) {\n const [a, b] = [Number(ipv4[1]), Number(ipv4[2])]\n return a === 0 || a === 10 || a === 127 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) ||\n (a === 192 && b === 168) || (a === 100 && b >= 64 && b <= 127)\n }\n if (!named.includes(':')) return false\n const groups = named.split(':')\n const allZero = (parts: string[]) => parts.every((part) => /^0*$/.test(part))\n // :: and ::1 in any spelling (0:0:0:0:0:0:0:1), then the private and link-local prefixes.\n if (allZero(groups) || (allZero(groups.slice(0, -1)) && /^0*1$/.test(groups.at(-1) ?? ''))) return true\n return /^f[cd][0-9a-f]{0,2}:/.test(named) || /^fe[89ab][0-9a-f]?:/.test(named)\n}\n\n/** One address in each local range, to judge a wildcard host by. */\nconst LOCAL_HOST_SAMPLES = ['localhost', 'a.localhost', '0.0.0.0', '10.0.0.1', '100.64.0.1', '127.0.0.1', '169.254.169.254', '172.16.0.1', '192.168.0.1', '::1', 'fc00::1', 'fe80::1']\n\nfunction describeRemotePattern(pattern: BrandlabNextRemotePattern): string {\n const path = pattern.pathname === undefined ? '/**' : pattern.pathname.startsWith('/') ? pattern.pathname : `/${pattern.pathname}`\n return `${pattern.protocol ?? 'any protocol'}://${pattern.hostname}${pattern.port ? `:${pattern.port}` : ''}${path}`\n}\n\n/** A validated copy of a remote pattern list: the keys and value types Next reads. */\nfunction remotePatternList(value: unknown, field: string): BrandlabNextRemotePattern[] | undefined {\n if (value === undefined) return undefined\n if (!Array.isArray(value)) throw new Error(`images.${field} must be an array.`)\n return value.map((pattern: unknown, index) => {\n const at = `images.${field}[${index}]`\n if (!pattern || typeof pattern !== 'object' || Array.isArray(pattern)) {\n throw new Error(`${at} must be a { protocol, hostname, port?, pathname?, search? } pattern.`)\n }\n assertKnownKeys(pattern, REMOTE_PATTERN_KEYS, at)\n const record = pattern as Record<string, unknown>\n if (typeof record.hostname !== 'string' || !record.hostname.trim()) throw new Error(`${at}.hostname must name a host.`)\n if (record.protocol !== undefined && record.protocol !== 'https' && record.protocol !== 'http') {\n throw new Error(`${at}.protocol must be 'https' ('http' only in images.developmentRemotePatterns).`)\n }\n for (const key of ['port', 'pathname', 'search'] as const) {\n if (record[key] !== undefined && typeof record[key] !== 'string') throw new Error(`${at}.${key} must be a string.`)\n }\n return { ...(pattern as BrandlabNextRemotePattern) }\n })\n}\n\n/**\n * A production build fetches remote images only over https from a public host:\n * the optimiser fetches a remote pattern's images on any visitor's request\n * (GHSA-cjq9-62q9-8jv4), and an http or local source is a development convenience.\n */\nfunction assertProductionRemotePatterns(patterns: readonly BrandlabNextRemotePattern[]) {\n patterns.forEach((pattern, index) => {\n const problems = [\n ...(pattern.protocol === 'https' ? [] : [pattern.protocol === 'http' ? 'uses http' : \"does not name protocol 'https'\"]),\n ...(isLocalImageHost(pattern.hostname)\n ? [/[*?{}[\\]()!@+]/.test(pattern.hostname) ? `admits local addresses (${pattern.hostname} can match localhost or a private address)` : `names the local address ${pattern.hostname}`]\n : []),\n ]\n if (problems.length === 0) return\n throw new Error(\n `images.remotePatterns[${index}] (${describeRemotePattern(pattern)}) ${problems.join(' and ')}. ` +\n 'A production build only fetches remote images over https from a public host. Remove the pattern, ' +\n 'or move a development-only source to images.developmentRemotePatterns, which only next dev uses.',\n )\n })\n}\n\nfunction buildImagesConfig(images: BrandlabNextImagesOptions, productionBuild: boolean): BrandlabNextImagesConfig {\n if (!images || typeof images !== 'object' || Array.isArray(images)) {\n throw new Error('images must declare the site image settings ({} for Next defaults).')\n }\n assertKnownKeys(images, IMAGE_KEYS, 'images', ' The output format is always image/webp.')\n const deviceSizes = positiveIntegers(images.deviceSizes, 'deviceSizes')\n const imageSizes = positiveIntegers(images.imageSizes, 'imageSizes')\n const qualities = positiveIntegers(images.qualities, 'qualities')\n if (qualities?.some((quality) => quality > 100)) {\n throw new Error('images.qualities must be between 1 and 100.')\n }\n if (\n images.minimumCacheTTL !== undefined &&\n (!Number.isSafeInteger(images.minimumCacheTTL) || images.minimumCacheTTL < 0)\n ) {\n throw new Error('images.minimumCacheTTL must be a non-negative integer of seconds.')\n }\n const remotePatterns = remotePatternList(images.remotePatterns, 'remotePatterns')\n const developmentRemotePatterns = remotePatternList(images.developmentRemotePatterns, 'developmentRemotePatterns')\n if (productionBuild && remotePatterns) assertProductionRemotePatterns(remotePatterns)\n // next dev (and tests) also fetch the development-only sources; a production build never does.\n const served = productionBuild || !developmentRemotePatterns?.length\n ? remotePatterns\n : [...(remotePatterns ?? []), ...developmentRemotePatterns]\n return {\n formats: ['image/webp'],\n ...(deviceSizes ? { deviceSizes } : {}),\n ...(imageSizes ? { imageSizes } : {}),\n ...(qualities ? { qualities } : {}),\n ...(images.minimumCacheTTL !== undefined ? { minimumCacheTTL: images.minimumCacheTTL } : {}),\n ...(served ? { remotePatterns: served } : {}),\n }\n}\n\nconst PAGE_OR_ROUTE_FILE = /^(?:page|route)\\.[A-Za-z0-9]+$/\nconst METADATA_ROUTE_FILE = /^(?:opengraph-image|twitter-image|icon|apple-icon|sitemap|robots|manifest)(?:[\\w.-]*)\\.[A-Za-z0-9]+$/\n\nfunction isDirectory(path: string) {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n\n/**\n * The first route file under an app directory that can answer a path strictly\n * below `/<folder>/`. `depth` counts the folder segments matched so far: route\n * groups, intercepts and parallel slots add none, a dynamic segment matches any\n * one, and a catch-all reaches every path below the folder.\n */\nfunction routeBelowFolder(\n directory: string,\n folder: readonly string[],\n depth: number,\n relative: string,\n): string | null {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const name = entry.name\n if (name.startsWith('_') || name.startsWith('.') || name === 'node_modules') continue\n const path = join(directory, name)\n const nextRelative = posix.join(relative, name)\n if (entry.isFile()) {\n // Page and route files serve their own directory; metadata files serve a path below it.\n const below = depth > folder.length && PAGE_OR_ROUTE_FILE.test(name)\n const metadata = depth >= folder.length && METADATA_ROUTE_FILE.test(name)\n if (below || metadata) return nextRelative\n continue\n }\n if (!entry.isDirectory()) continue\n let next: number | null = null\n if (name.startsWith('(') || name.startsWith('@')) next = depth\n else if (/^\\[\\[?\\.\\.\\./.test(name)) next = folder.length + 1\n else if (depth >= folder.length || name.startsWith('[') || name === folder[depth]) next = depth + 1\n if (next === null) continue\n const found = routeBelowFolder(path, folder, next, nextRelative)\n if (found) return found\n }\n return null\n}\n\n/** Each declared folder exists under public/ and no app route answers below it. */\nfunction assertStaticAssetFolders(folders: readonly BrandlabStaticAssetFolder[], root: string) {\n for (const { source, folder } of folders) {\n const publicFolder = posix.join('public', ...folder)\n if (!isDirectory(join(root, publicFolder))) {\n throw new Error(`staticAssetCache \"${source}\": ${publicFolder} is not a folder of static files in ${root}.`)\n }\n for (const appDirectory of ['src/app', 'app']) {\n if (!isDirectory(join(root, appDirectory))) continue\n const route = routeBelowFolder(join(root, appDirectory), folder, 0, appDirectory)\n if (route) {\n throw new Error(\n `staticAssetCache \"${source}\": ${route} answers below /${folder.join('/')}, so immutable caching could reach a page or route.`,\n )\n }\n }\n }\n}\n\n/** A site icon set, checked again here: the config may be handed an object that never went through defineSiteIcons. */\nfunction siteIconSet(site: unknown): SiteIconSet | undefined {\n if (site === undefined) return undefined\n const set = site as Partial<SiteIconSet>\n if (!set || typeof set !== 'object' || !Array.isArray(set.names) || !set.glyphs || typeof set.glyphs !== 'object') {\n throw new Error('icons.site must come from defineSiteIcons.')\n }\n return defineSiteIcons(Object.fromEntries(set.names.map((name) => [name, set.glyphs![name]!])))\n}\n\n/**\n * Converts the redirect table to Next redirects: each entry keeps its 301 or\n * 308 status (Next forwards the query string), gains a single-hop\n * trailing-slash variant, then one trailing-slash rule and one permanent\n * canonical-host rule per alias host follow. There is no x-forwarded-proto\n * rule: Vercel's edge already enforces HTTPS.\n */\nexport function buildBrandlabRedirects(options: {\n site: BrandlabSite\n redirects: BrandlabRedirectTable\n /** next.config's alias hosts, after the site identity's own (3.2.1). */\n aliasHosts?: readonly string[]\n}): BrandlabNextRedirect[] {\n const aliasHosts = brandlabAliasHosts(options.site, options.aliasHosts)\n const table = defineRedirects(options.redirects)\n const entries = table.flatMap((redirect): BrandlabNextRedirect[] => {\n const status = redirect.status === 301\n ? { statusCode: 301 as const }\n : { permanent: true as const }\n const has = redirect.host ? { has: [{ type: 'host' as const, value: redirect.host }] } : {}\n const record = (source: string): BrandlabNextRedirect => ({\n source,\n destination: redirect.destination,\n ...status,\n ...has,\n })\n return redirect.source === '/'\n ? [record(redirect.source)]\n : [record(redirect.source), record(`${redirect.source}/`)]\n })\n return [\n ...entries,\n { source: '/:path+/', destination: '/:path+', permanent: true },\n ...aliasHosts.map((host): BrandlabNextRedirect => ({\n source: '/:path*',\n has: [{ type: 'host', value: host }],\n destination: `${options.site.canonicalUrl}/:path*`,\n permanent: true,\n })),\n ]\n}\n\n/**\n * Every alias host: the site identity's (the 3.0–3.2.0 place) then next.config's\n * (3.2.1), validated together so a host is never declared twice.\n */\nexport function brandlabAliasHosts(site: BrandlabSite, aliasHosts: readonly string[] | undefined): readonly string[] {\n if (aliasHosts === undefined) return site.aliasHosts\n assertBrandlabAliasHosts(aliasHosts, site.canonicalHost ?? new URL(site.canonicalUrl).hostname, 'next.config aliasHosts')\n const all = [...site.aliasHosts, ...aliasHosts]\n const duplicate = all.find((host, index) => all.indexOf(host) !== index)\n if (duplicate) throw new Error(`Alias host \"${duplicate}\" is declared in both the site identity and next.config aliasHosts.`)\n return all\n}\n\n/**\n * The whole next.config.ts after its first line\n * `import '@brandlab-digital/site-next/image-runtime'`:\n * `export default defineBrandlabNextConfig({ site, redirects, images })`.\n *\n * Sets poweredByHeader: false, WebP image output, Sharp output tracing for\n * /api/contact, NEXT_PUBLIC_VERCEL_ENV for browser gates, the deployment's\n * header rules (with immutable caching for the declared static public folders on\n * production builds) and the redirect table. Validation runs when the config\n * loads, so an invalid table, header exception or static folder fails the build,\n * as does (3.3.3) a production build's http or local image remote pattern.\n */\nexport function defineBrandlabNextConfig(\n options: BrandlabNextConfigOptions & { mdx?: undefined },\n): BrandlabNextConfig\nexport function defineBrandlabNextConfig<Wrapped>(\n options: BrandlabNextConfigOptions & {\n /** The @next/mdx wrapper: createMDX({ options: { remarkPlugins: ['remark-gfm'] } }). */\n mdx: (config: BrandlabNextConfig) => Wrapped\n },\n): Wrapped\nexport function defineBrandlabNextConfig(\n options: BrandlabNextConfigOptions & { mdx?: (config: BrandlabNextConfig) => unknown },\n): unknown {\n if (!options || typeof options !== 'object') {\n throw new TypeError('defineBrandlabNextConfig requires the site, redirects and images.')\n }\n assertKnownKeys(options, OPTION_KEYS, 'next.config options')\n if (!options.site?.canonicalUrl || !Array.isArray(options.site.aliasHosts)) {\n throw new Error('site must come from defineBrandlabSite.')\n }\n if (options.mdx !== undefined && typeof options.mdx !== 'function') {\n throw new TypeError('mdx must be the @next/mdx config wrapper.')\n }\n const deployment = resolveBrandlabDeployment(options.environment ?? process.env)\n if (options.staticAssetCache !== undefined) {\n assertStaticAssetFolders(\n parseBrandlabStaticAssetCache(options.staticAssetCache),\n options.projectRoot ?? process.cwd(),\n )\n }\n const headerRules = buildBrandlabHeaderRules({\n deployment,\n canonicalHost: options.site.canonicalHost ?? new URL(options.site.canonicalUrl).hostname,\n ...(options.csp ? { contentSecurityPolicyExtensions: options.csp } : {}),\n ...(options.hsts ? { hsts: options.hsts } : {}),\n ...(options.permissionsPolicy ? { permissionsPolicy: options.permissionsPolicy } : {}),\n ...(options.extraHeaders ? { extraHeaders: options.extraHeaders } : {}),\n ...(options.staticAssetCache ? { staticAssetCache: options.staticAssetCache } : {}),\n })\n if (options.icons !== undefined) {\n if (!options.icons || typeof options.icons !== 'object' || Array.isArray(options.icons)) {\n throw new Error('icons must be { site?: defineSiteIcons(...) } ({} for the library icons only).')\n }\n assertKnownKeys(options.icons, new Set(['site']), 'icons')\n }\n const sprite = options.icons === undefined ? undefined : writeIconSprite(options.projectRoot ?? process.cwd(), siteIconSet(options.icons.site))\n // The same production-only rule as staticAssetCache: Previews keep private, no-store.\n if (sprite && deployment.productionBuild && deployment.environment !== 'preview') {\n // After the static folders, before the non-canonical host rule.\n const at = headerRules.findIndex((rule) => rule.missing !== undefined)\n headerRules.splice(at === -1 ? headerRules.length : at, 0, {\n source: BRANDLAB_ICON_SPRITE_SOURCE,\n headers: [{ key: 'Cache-Control', value: BRANDLAB_STATIC_ASSET_CACHE_CONTROL }],\n })\n }\n const redirects = buildBrandlabRedirects({\n site: options.site,\n redirects: options.redirects,\n ...(options.aliasHosts !== undefined ? { aliasHosts: options.aliasHosts } : {}),\n })\n\n const config: BrandlabNextConfig = {\n poweredByHeader: false,\n skipTrailingSlashRedirect: true,\n env: {\n NEXT_PUBLIC_VERCEL_ENV: deployment.environment,\n ...(sprite ? { [ICON_SPRITE_ENV]: sprite.href } : {}),\n },\n outputFileTracingIncludes: Object.fromEntries(\n Object.entries(BRANDLAB_CONTACT_OUTPUT_FILE_TRACING).map(([route, globs]) => [route, [...globs]]),\n ),\n // A Vercel build (preview or production) is checked like any production build, whatever NODE_ENV says.\n images: buildImagesConfig(options.images, deployment.productionBuild || deployment.environment !== 'development'),\n ...(options.mdx ? { pageExtensions: [...MDX_PAGE_EXTENSIONS] } : {}),\n headers: async () =>\n headerRules.map((rule) => ({\n source: rule.source,\n ...(rule.missing ? { missing: rule.missing.map((condition) => ({ ...condition })) } : {}),\n headers: rule.headers.map((header) => ({ ...header })),\n })),\n redirects: async () =>\n redirects.map((redirect) => ({\n ...redirect,\n ...(redirect.has ? { has: redirect.has.map((condition) => ({ ...condition })) } : {}),\n })),\n }\n return options.mdx ? options.mdx(config) : config\n}\n"]}
|
package/dist/robots.d.ts
CHANGED
|
@@ -1,12 +1,36 @@
|
|
|
1
1
|
import { type BrandlabDeployment, type BrandlabEnvironment, type BrandlabSite } from '@brandlab-digital/site-core/site';
|
|
2
2
|
export interface BrandlabRobotsMetadata {
|
|
3
3
|
rules: Array<{
|
|
4
|
-
userAgent: string;
|
|
4
|
+
userAgent: string | string[];
|
|
5
5
|
allow?: string;
|
|
6
6
|
disallow?: string | string[];
|
|
7
|
+
crawlDelay?: number;
|
|
7
8
|
}>;
|
|
8
9
|
sitemap?: string;
|
|
9
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* A named robots.txt group (3.13.0), for a crawler that needs its own rules, such as Meta's under a recorded
|
|
13
|
+
* decision. The group keeps every shared disallow and adds its own. A search or answer crawler
|
|
14
|
+
* (`BRANDLAB_SEARCH_CRAWLERS`) can never be shut out of the whole site, and the ready gate (W10) checks the built file.
|
|
15
|
+
*/
|
|
16
|
+
export interface BrandlabRobotsBotPolicy {
|
|
17
|
+
/** The crawler's robots.txt token or tokens, for example `meta-externalagent`. Never `*`. */
|
|
18
|
+
userAgent: string | readonly string[];
|
|
19
|
+
/** Paths kept off for these crawlers on top of the shared disallows, each starting with "/". */
|
|
20
|
+
disallow?: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* Seconds between requests, only with the id of a recorded decision. Google ignores Crawl-delay and Bing honours
|
|
23
|
+
* it, so it slows Bing indexing; a delay on a search or answer crawler also needs a Romie-owned W10 exception.
|
|
24
|
+
*/
|
|
25
|
+
crawlDelay?: {
|
|
26
|
+
seconds: number;
|
|
27
|
+
decision: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface BrandlabRobotsOptions {
|
|
31
|
+
environment?: BrandlabEnvironment;
|
|
32
|
+
botPolicies?: readonly BrandlabRobotsBotPolicy[];
|
|
33
|
+
}
|
|
10
34
|
/**
|
|
11
35
|
* Crawlers may index any production build except a Vercel Preview: the real
|
|
12
36
|
* production deployment and a local `next start`. `next dev` and every
|
|
@@ -19,7 +43,5 @@ export declare function isBrandlabIndexableDeployment(deployment: BrandlabDeploy
|
|
|
19
43
|
* everything but the shared API routes and names the canonical sitemap; every
|
|
20
44
|
* other deployment keeps `Disallow: /`.
|
|
21
45
|
*/
|
|
22
|
-
export declare function createBrandlabRobots(site: BrandlabSite, options?:
|
|
23
|
-
environment?: BrandlabEnvironment;
|
|
24
|
-
}): () => BrandlabRobotsMetadata;
|
|
46
|
+
export declare function createBrandlabRobots(site: BrandlabSite, options?: BrandlabRobotsOptions): () => BrandlabRobotsMetadata;
|
|
25
47
|
//# sourceMappingURL=robots.d.ts.map
|
package/dist/robots.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAClB,MAAM,kCAAkC,CAAA;AAEzC,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,6FAA6F;IAC7F,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IACrC,gGAAgG;IAChG,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CACnD;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,mBAAmB,CAAA;IACjC,WAAW,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAA;CACjD;AAYD;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,kBAAkB,WAG3E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,OAAO,GAAE,qBAA0B,SAOT,sBAAsB,CAajD"}
|
package/dist/robots.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveBrandlabDeployment, } from '@brandlab-digital/site-core/site';
|
|
1
|
+
import { brandlabSearchCrawlerNamed, resolveBrandlabDeployment, } from '@brandlab-digital/site-core/site';
|
|
2
2
|
/**
|
|
3
3
|
* The shared API routes crawlers have no use for, kept out of a production
|
|
4
4
|
* robots.txt (from 3.3.0): the contact endpoint. A robots.txt path is a prefix, so
|
|
@@ -25,6 +25,11 @@ export function isBrandlabIndexableDeployment(deployment) {
|
|
|
25
25
|
*/
|
|
26
26
|
export function createBrandlabRobots(site, options = {}) {
|
|
27
27
|
const sitemap = `${site.canonicalUrl}/sitemap.xml`;
|
|
28
|
+
const groups = (options.botPolicies ?? []).map(botPolicyRule);
|
|
29
|
+
const named = groups.flatMap((group) => [group.userAgent].flat().map((token) => token.toLowerCase()));
|
|
30
|
+
const repeated = named.find((token, index) => named.indexOf(token) !== index);
|
|
31
|
+
if (repeated)
|
|
32
|
+
throw new Error(`botPolicies names "${repeated}" twice; give each crawler one group.`);
|
|
28
33
|
return function robots() {
|
|
29
34
|
const deployment = resolveBrandlabDeployment(options.environment ?? process.env);
|
|
30
35
|
if (!isBrandlabIndexableDeployment(deployment)) {
|
|
@@ -34,9 +39,51 @@ export function createBrandlabRobots(site, options = {}) {
|
|
|
34
39
|
// by Google and Bing; canonical-host consolidation is owned by permanent
|
|
35
40
|
// redirects and canonical URLs.
|
|
36
41
|
return {
|
|
37
|
-
rules: [{ userAgent: '*', allow: '/', disallow: [...SHARED_API_DISALLOW] }],
|
|
42
|
+
rules: [{ userAgent: '*', allow: '/', disallow: [...SHARED_API_DISALLOW] }, ...groups],
|
|
38
43
|
sitemap,
|
|
39
44
|
};
|
|
40
45
|
};
|
|
41
46
|
}
|
|
47
|
+
function botPolicyRule(policy, index) {
|
|
48
|
+
const field = `botPolicies[${index}]`;
|
|
49
|
+
if (!policy || typeof policy !== 'object')
|
|
50
|
+
throw new TypeError(`${field} must be an object.`);
|
|
51
|
+
const unknown = Object.keys(policy).filter((key) => !['userAgent', 'disallow', 'crawlDelay'].includes(key));
|
|
52
|
+
if (unknown.length > 0)
|
|
53
|
+
throw new Error(`${field} contains unsupported keys: ${unknown.join(', ')}.`);
|
|
54
|
+
const tokens = typeof policy.userAgent === 'string' ? [policy.userAgent] : [...(policy.userAgent ?? [])];
|
|
55
|
+
if (tokens.length === 0)
|
|
56
|
+
throw new Error(`${field}.userAgent must name a crawler.`);
|
|
57
|
+
for (const token of tokens) {
|
|
58
|
+
if (typeof token !== 'string' || !/^[A-Za-z0-9._-]+$/.test(token.trim()) || token !== token.trim()) {
|
|
59
|
+
throw new Error(`${field}.userAgent must be robots.txt crawler tokens such as "meta-externalagent" (found ${JSON.stringify(token)}); the shared group already covers "*".`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const disallow = [...(policy.disallow ?? [])];
|
|
63
|
+
for (const path of disallow) {
|
|
64
|
+
if (typeof path !== 'string' || !path.startsWith('/') || /\s/.test(path)) {
|
|
65
|
+
throw new Error(`${field}.disallow paths must start with "/" (found ${JSON.stringify(path)}).`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const protectedCrawler = tokens.map(brandlabSearchCrawlerNamed).find(Boolean);
|
|
69
|
+
if (protectedCrawler && disallow.some((path) => path === '/' || path === '/*')) {
|
|
70
|
+
throw new Error(`${field} shuts ${protectedCrawler} out of the whole site; search and answer crawlers stay allowed.`);
|
|
71
|
+
}
|
|
72
|
+
const rule = {
|
|
73
|
+
userAgent: tokens.length === 1 ? tokens[0] : tokens,
|
|
74
|
+
allow: '/',
|
|
75
|
+
disallow: [...new Set([...SHARED_API_DISALLOW, ...disallow])],
|
|
76
|
+
};
|
|
77
|
+
if (policy.crawlDelay !== undefined) {
|
|
78
|
+
const { seconds, decision } = policy.crawlDelay ?? {};
|
|
79
|
+
if (typeof decision !== 'string' || !decision.trim()) {
|
|
80
|
+
throw new Error(`${field}.crawlDelay needs the id of a recorded decision; Crawl-delay slows Bing indexing and Google ignores it.`);
|
|
81
|
+
}
|
|
82
|
+
if (typeof seconds !== 'number' || !Number.isFinite(seconds) || seconds <= 0 || seconds > 60) {
|
|
83
|
+
throw new Error(`${field}.crawlDelay.seconds must be a number of seconds from above 0 to 60.`);
|
|
84
|
+
}
|
|
85
|
+
rule.crawlDelay = seconds;
|
|
86
|
+
}
|
|
87
|
+
return rule;
|
|
88
|
+
}
|
|
42
89
|
//# sourceMappingURL=robots.js.map
|
package/dist/robots.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"robots.js","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,GAI1B,MAAM,kCAAkC,CAAA;AAOzC;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAG,CAAC,cAAc,CAAC,CAAA;AAE5C;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,UAA8B;IAC1E,OAAO,UAAU,CAAC,WAAW,KAAK,YAAY;QAC5C,CAAC,UAAU,CAAC,WAAW,KAAK,aAAa,IAAI,UAAU,CAAC,eAAe,CAAC,CAAA;AAC5E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAkB,EAClB,UAAiD,EAAE;IAEnD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,YAAY,cAAc,CAAA;IAClD,OAAO,SAAS,MAAM;QACpB,MAAM,UAAU,GAAG,yBAAyB,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,CAAA;QAChF,IAAI,CAAC,6BAA6B,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,CAAA;QACvD,CAAC;QACD,yEAAyE;QACzE,yEAAyE;QACzE,gCAAgC;QAChC,OAAO;YACL,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,GAAG,mBAAmB,CAAC,EAAE,CAAC;YAC3E,OAAO;SACR,CAAA;IACH,CAAC,CAAA;AACH,CAAC","sourcesContent":["import {\n resolveBrandlabDeployment,\n type BrandlabDeployment,\n type BrandlabEnvironment,\n type BrandlabSite,\n} from '@brandlab-digital/site-core/site'\n\nexport interface BrandlabRobotsMetadata {\n rules: Array<{ userAgent: string; allow?: string; disallow?: string | string[] }>\n sitemap?: string\n}\n\n/**\n * The shared API routes crawlers have no use for, kept out of a production\n * robots.txt (from 3.3.0): the contact endpoint. A robots.txt path is a prefix, so\n * it covers its subpaths. Only this: not a blanket `/api/`, because a site may serve\n * something public there. From 3.5.0 `/api/google-reviews` is no longer listed:\n * sites read Google reviews from the Brandlab reviews feed on the server\n * (`site-next/google-business-reviews/server`) and no longer serve that route.\n */\nconst SHARED_API_DISALLOW = ['/api/contact']\n\n/**\n * Crawlers may index any production build except a Vercel Preview: the real\n * production deployment and a local `next start`. `next dev` and every\n * Preview are closed. There is no environment override.\n */\nexport function isBrandlabIndexableDeployment(deployment: BrandlabDeployment) {\n return deployment.environment === 'production' ||\n (deployment.environment === 'development' && deployment.productionBuild)\n}\n\n/**\n * `src/app/robots.ts`: `export default createBrandlabRobots(site)`.\n * The deployment is resolved when Next renders robots.txt. Production allows\n * everything but the shared API routes and names the canonical sitemap; every\n * other deployment keeps `Disallow: /`.\n */\nexport function createBrandlabRobots(\n site: BrandlabSite,\n options: { environment?: BrandlabEnvironment } = {},\n) {\n const sitemap = `${site.canonicalUrl}/sitemap.xml`\n return function robots(): BrandlabRobotsMetadata {\n const deployment = resolveBrandlabDeployment(options.environment ?? process.env)\n if (!isBrandlabIndexableDeployment(deployment)) {\n return { rules: [{ userAgent: '*', disallow: '/' }] }\n }\n // No `host` directive: it is a non-standard robots.txt extension ignored\n // by Google and Bing; canonical-host consolidation is owned by permanent\n // redirects and canonical URLs.\n return {\n rules: [{ userAgent: '*', allow: '/', disallow: [...SHARED_API_DISALLOW] }],\n sitemap,\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"robots.js","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n brandlabSearchCrawlerNamed,\n resolveBrandlabDeployment,\n type BrandlabDeployment,\n type BrandlabEnvironment,\n type BrandlabSite,\n} from '@brandlab-digital/site-core/site'\n\nexport interface BrandlabRobotsMetadata {\n rules: Array<{ userAgent: string | string[]; allow?: string; disallow?: string | string[]; crawlDelay?: number }>\n sitemap?: string\n}\n\n/**\n * A named robots.txt group (3.13.0), for a crawler that needs its own rules, such as Meta's under a recorded\n * decision. The group keeps every shared disallow and adds its own. A search or answer crawler\n * (`BRANDLAB_SEARCH_CRAWLERS`) can never be shut out of the whole site, and the ready gate (W10) checks the built file.\n */\nexport interface BrandlabRobotsBotPolicy {\n /** The crawler's robots.txt token or tokens, for example `meta-externalagent`. Never `*`. */\n userAgent: string | readonly string[]\n /** Paths kept off for these crawlers on top of the shared disallows, each starting with \"/\". */\n disallow?: readonly string[]\n /**\n * Seconds between requests, only with the id of a recorded decision. Google ignores Crawl-delay and Bing honours\n * it, so it slows Bing indexing; a delay on a search or answer crawler also needs a Romie-owned W10 exception.\n */\n crawlDelay?: { seconds: number; decision: string }\n}\n\nexport interface BrandlabRobotsOptions {\n environment?: BrandlabEnvironment\n botPolicies?: readonly BrandlabRobotsBotPolicy[]\n}\n\n/**\n * The shared API routes crawlers have no use for, kept out of a production\n * robots.txt (from 3.3.0): the contact endpoint. A robots.txt path is a prefix, so\n * it covers its subpaths. Only this: not a blanket `/api/`, because a site may serve\n * something public there. From 3.5.0 `/api/google-reviews` is no longer listed:\n * sites read Google reviews from the Brandlab reviews feed on the server\n * (`site-next/google-business-reviews/server`) and no longer serve that route.\n */\nconst SHARED_API_DISALLOW = ['/api/contact']\n\n/**\n * Crawlers may index any production build except a Vercel Preview: the real\n * production deployment and a local `next start`. `next dev` and every\n * Preview are closed. There is no environment override.\n */\nexport function isBrandlabIndexableDeployment(deployment: BrandlabDeployment) {\n return deployment.environment === 'production' ||\n (deployment.environment === 'development' && deployment.productionBuild)\n}\n\n/**\n * `src/app/robots.ts`: `export default createBrandlabRobots(site)`.\n * The deployment is resolved when Next renders robots.txt. Production allows\n * everything but the shared API routes and names the canonical sitemap; every\n * other deployment keeps `Disallow: /`.\n */\nexport function createBrandlabRobots(\n site: BrandlabSite,\n options: BrandlabRobotsOptions = {},\n) {\n const sitemap = `${site.canonicalUrl}/sitemap.xml`\n const groups = (options.botPolicies ?? []).map(botPolicyRule)\n const named = groups.flatMap((group) => [group.userAgent].flat().map((token) => token.toLowerCase()))\n const repeated = named.find((token, index) => named.indexOf(token) !== index)\n if (repeated) throw new Error(`botPolicies names \"${repeated}\" twice; give each crawler one group.`)\n return function robots(): BrandlabRobotsMetadata {\n const deployment = resolveBrandlabDeployment(options.environment ?? process.env)\n if (!isBrandlabIndexableDeployment(deployment)) {\n return { rules: [{ userAgent: '*', disallow: '/' }] }\n }\n // No `host` directive: it is a non-standard robots.txt extension ignored\n // by Google and Bing; canonical-host consolidation is owned by permanent\n // redirects and canonical URLs.\n return {\n rules: [{ userAgent: '*', allow: '/', disallow: [...SHARED_API_DISALLOW] }, ...groups],\n sitemap,\n }\n }\n}\n\nfunction botPolicyRule(policy: BrandlabRobotsBotPolicy, index: number): BrandlabRobotsMetadata['rules'][number] {\n const field = `botPolicies[${index}]`\n if (!policy || typeof policy !== 'object') throw new TypeError(`${field} must be an object.`)\n const unknown = Object.keys(policy).filter((key) => !['userAgent', 'disallow', 'crawlDelay'].includes(key))\n if (unknown.length > 0) throw new Error(`${field} contains unsupported keys: ${unknown.join(', ')}.`)\n const tokens = typeof policy.userAgent === 'string' ? [policy.userAgent] : [...(policy.userAgent ?? [])]\n if (tokens.length === 0) throw new Error(`${field}.userAgent must name a crawler.`)\n for (const token of tokens) {\n if (typeof token !== 'string' || !/^[A-Za-z0-9._-]+$/.test(token.trim()) || token !== token.trim()) {\n throw new Error(`${field}.userAgent must be robots.txt crawler tokens such as \"meta-externalagent\" (found ${JSON.stringify(token)}); the shared group already covers \"*\".`)\n }\n }\n const disallow = [...(policy.disallow ?? [])]\n for (const path of disallow) {\n if (typeof path !== 'string' || !path.startsWith('/') || /\\s/.test(path)) {\n throw new Error(`${field}.disallow paths must start with \"/\" (found ${JSON.stringify(path)}).`)\n }\n }\n const protectedCrawler = tokens.map(brandlabSearchCrawlerNamed).find(Boolean)\n if (protectedCrawler && disallow.some((path) => path === '/' || path === '/*')) {\n throw new Error(`${field} shuts ${protectedCrawler} out of the whole site; search and answer crawlers stay allowed.`)\n }\n const rule: BrandlabRobotsMetadata['rules'][number] = {\n userAgent: tokens.length === 1 ? tokens[0]! : tokens,\n allow: '/',\n disallow: [...new Set([...SHARED_API_DISALLOW, ...disallow])],\n }\n if (policy.crawlDelay !== undefined) {\n const { seconds, decision } = policy.crawlDelay ?? ({} as { seconds?: unknown; decision?: unknown })\n if (typeof decision !== 'string' || !decision.trim()) {\n throw new Error(`${field}.crawlDelay needs the id of a recorded decision; Crawl-delay slows Bing indexing and Google ignores it.`)\n }\n if (typeof seconds !== 'number' || !Number.isFinite(seconds) || seconds <= 0 || seconds > 60) {\n throw new Error(`${field}.crawlDelay.seconds must be a number of seconds from above 0 to 60.`)\n }\n rule.crawlDelay = seconds\n }\n return rule\n}\n"]}
|
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { ButtonLinkSkin, PhoneLinkSkin, TextLinkSkin } from './primitives/links.js';
|
|
7
7
|
import type { QuoteButtonSkin } from './primitives/quote-button.js';
|
|
8
|
-
import type { ContainerSkin, SectionHeadingSkin } from './primitives/layout.js';
|
|
8
|
+
import type { ContainerSkin, EyebrowSkin, SectionHeadingSkin } from './primitives/layout.js';
|
|
9
|
+
import type { BadgeSkin, ChipSkin } from './primitives/badge.js';
|
|
10
|
+
import type { ButtonSkin } from './primitives/button.js';
|
|
11
|
+
import type { CardSkin } from './primitives/card.js';
|
|
12
|
+
import type { LinkListSkin, TickListSkin } from './primitives/lists.js';
|
|
13
|
+
import type { MediaFrameSkin } from './primitives/media-frame.js';
|
|
14
|
+
import type { StatSkin } from './primitives/stat.js';
|
|
9
15
|
import type { BackToTopSkin } from './shell/back-to-top.js';
|
|
10
16
|
import type { MobileCallBarSkin } from './shell/mobile-call-bar.js';
|
|
11
17
|
import type { MobileDrawerSkin } from './shell/mobile-drawer.js';
|
|
@@ -28,6 +34,10 @@ import type { PageHeaderSkin } from './sections/page-header.js';
|
|
|
28
34
|
import type { PriceGuideSkin } from './sections/price-guide.js';
|
|
29
35
|
import type { PriceTableSkin } from './sections/price-table.js';
|
|
30
36
|
import type { ProofStripSkin } from './sections/proof-strip.js';
|
|
37
|
+
import type { HeroSkin } from './sections/hero.js';
|
|
38
|
+
import type { ServicesGridSkin } from './sections/services-grid.js';
|
|
39
|
+
import type { MediaSkin } from './primitives/media.js';
|
|
40
|
+
import type { BreadcrumbsSkin } from './primitives/breadcrumbs.js';
|
|
31
41
|
export interface BrandlabSkin {
|
|
32
42
|
readonly buttonLink?: ButtonLinkSkin;
|
|
33
43
|
readonly textLink?: TextLinkSkin;
|
|
@@ -35,6 +45,15 @@ export interface BrandlabSkin {
|
|
|
35
45
|
readonly quoteButton?: QuoteButtonSkin;
|
|
36
46
|
readonly container?: ContainerSkin;
|
|
37
47
|
readonly sectionHeading?: SectionHeadingSkin;
|
|
48
|
+
readonly button?: ButtonSkin;
|
|
49
|
+
readonly eyebrow?: EyebrowSkin;
|
|
50
|
+
readonly card?: CardSkin;
|
|
51
|
+
readonly badge?: BadgeSkin;
|
|
52
|
+
readonly chip?: ChipSkin;
|
|
53
|
+
readonly stat?: StatSkin;
|
|
54
|
+
readonly tickList?: TickListSkin;
|
|
55
|
+
readonly linkList?: LinkListSkin;
|
|
56
|
+
readonly mediaFrame?: MediaFrameSkin;
|
|
38
57
|
readonly siteHeader?: SiteHeaderSkin;
|
|
39
58
|
readonly mobileDrawer?: MobileDrawerSkin;
|
|
40
59
|
readonly utilityBar?: UtilityBarSkin;
|
|
@@ -57,5 +76,9 @@ export interface BrandlabSkin {
|
|
|
57
76
|
readonly proofStrip?: ProofStripSkin;
|
|
58
77
|
readonly pageHeader?: PageHeaderSkin;
|
|
59
78
|
readonly contactBlock?: ContactBlockSkin;
|
|
79
|
+
readonly hero?: HeroSkin;
|
|
80
|
+
readonly servicesGrid?: ServicesGridSkin;
|
|
81
|
+
readonly media?: MediaSkin;
|
|
82
|
+
readonly breadcrumbs?: BreadcrumbsSkin;
|
|
60
83
|
}
|
|
61
84
|
//# sourceMappingURL=brandlab-skin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brandlab-skin.d.ts","sourceRoot":"","sources":["../../src/ui-kit/brandlab-skin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"brandlab-skin.d.ts","sourceRoot":"","sources":["../../src/ui-kit/brandlab-skin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC5F,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAElE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAA;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAA;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAA;IAClC,QAAQ,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAA;IAE5C,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAA;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAA;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAA;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAA;IAElC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAA;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAA;IACtC,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAA;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAA;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAA;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAA;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAA;IAExC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;IAExB,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAA;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAA;CACvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brandlab-skin.js","sourceRoot":"","sources":["../../src/ui-kit/brandlab-skin.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A site's whole look for the ui-kit: one entry per shared component it renders (`src/site/skin.ts`, written with\n * `satisfies BrandlabSkin`). Each release adds the entries for its components. K2 checks that every rendered\n * component has an entry and that no reference-skin class ships.\n */\nimport type { ButtonLinkSkin, PhoneLinkSkin, TextLinkSkin } from './primitives/links.js'\nimport type { QuoteButtonSkin } from './primitives/quote-button.js'\nimport type { ContainerSkin, SectionHeadingSkin } from './primitives/layout.js'\nimport type { BackToTopSkin } from './shell/back-to-top.js'\nimport type { MobileCallBarSkin } from './shell/mobile-call-bar.js'\nimport type { MobileDrawerSkin } from './shell/mobile-drawer.js'\nimport type { SiteHeaderSkin } from './shell/site-header.js'\nimport type { UtilityBarSkin } from './shell/utility-bar.js'\nimport type { DialogSkin } from './form/dialog.js'\nimport type { FieldSkin } from './form/field.js'\nimport type { PhotoUploadSkin } from './form/photo-upload.js'\nimport type { QuoteDialogSkin } from './form/quote-dialog.js'\nimport type { QuoteFormSkin } from './form/quote-form.js'\nimport type { ThankYouSkin } from './form/thank-you.js'\nimport type { CTABandSkin } from './sections/cta-band.js'\nimport type { RatingChipSkin } from './sections/rating-chip.js'\nimport type { ReviewsBandSkin } from './sections/reviews-band.js'\nimport type { SiteFooterSkin } from './sections/site-footer.js'\nimport type { AccordionSkin } from './sections/accordion.js'\nimport type { ContactBlockSkin } from './sections/contact-block.js'\nimport type { FAQsSkin } from './sections/faqs.js'\nimport type { PageHeaderSkin } from './sections/page-header.js'\nimport type { PriceGuideSkin } from './sections/price-guide.js'\nimport type { PriceTableSkin } from './sections/price-table.js'\nimport type { ProofStripSkin } from './sections/proof-strip.js'\n\nexport interface BrandlabSkin {\n readonly buttonLink?: ButtonLinkSkin\n readonly textLink?: TextLinkSkin\n readonly phoneLink?: PhoneLinkSkin\n readonly quoteButton?: QuoteButtonSkin\n readonly container?: ContainerSkin\n readonly sectionHeading?: SectionHeadingSkin\n readonly siteHeader?: SiteHeaderSkin\n readonly mobileDrawer?: MobileDrawerSkin\n readonly utilityBar?: UtilityBarSkin\n readonly mobileCallBar?: MobileCallBarSkin\n readonly backToTop?: BackToTopSkin\n // form (3.10.0)\n readonly quoteForm?: QuoteFormSkin\n readonly quoteDialog?: QuoteDialogSkin\n readonly photoUpload?: PhotoUploadSkin\n readonly dialog?: DialogSkin\n readonly field?: FieldSkin\n readonly thankYou?: ThankYouSkin\n readonly ratingChip?: RatingChipSkin\n readonly reviewsBand?: ReviewsBandSkin\n readonly ctaBand?: CTABandSkin\n readonly siteFooter?: SiteFooterSkin\n readonly accordion?: AccordionSkin\n readonly faqs?: FAQsSkin\n readonly priceTable?: PriceTableSkin\n readonly priceGuide?: PriceGuideSkin\n readonly proofStrip?: ProofStripSkin\n readonly pageHeader?: PageHeaderSkin\n readonly contactBlock?: ContactBlockSkin\n}\n"]}
|
|
1
|
+
{"version":3,"file":"brandlab-skin.js","sourceRoot":"","sources":["../../src/ui-kit/brandlab-skin.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A site's whole look for the ui-kit: one entry per shared component it renders (`src/site/skin.ts`, written with\n * `satisfies BrandlabSkin`). Each release adds the entries for its components. K2 checks that every rendered\n * component has an entry and that no reference-skin class ships.\n */\nimport type { ButtonLinkSkin, PhoneLinkSkin, TextLinkSkin } from './primitives/links.js'\nimport type { QuoteButtonSkin } from './primitives/quote-button.js'\nimport type { ContainerSkin, EyebrowSkin, SectionHeadingSkin } from './primitives/layout.js'\nimport type { BadgeSkin, ChipSkin } from './primitives/badge.js'\nimport type { ButtonSkin } from './primitives/button.js'\nimport type { CardSkin } from './primitives/card.js'\nimport type { LinkListSkin, TickListSkin } from './primitives/lists.js'\nimport type { MediaFrameSkin } from './primitives/media-frame.js'\nimport type { StatSkin } from './primitives/stat.js'\nimport type { BackToTopSkin } from './shell/back-to-top.js'\nimport type { MobileCallBarSkin } from './shell/mobile-call-bar.js'\nimport type { MobileDrawerSkin } from './shell/mobile-drawer.js'\nimport type { SiteHeaderSkin } from './shell/site-header.js'\nimport type { UtilityBarSkin } from './shell/utility-bar.js'\nimport type { DialogSkin } from './form/dialog.js'\nimport type { FieldSkin } from './form/field.js'\nimport type { PhotoUploadSkin } from './form/photo-upload.js'\nimport type { QuoteDialogSkin } from './form/quote-dialog.js'\nimport type { QuoteFormSkin } from './form/quote-form.js'\nimport type { ThankYouSkin } from './form/thank-you.js'\nimport type { CTABandSkin } from './sections/cta-band.js'\nimport type { RatingChipSkin } from './sections/rating-chip.js'\nimport type { ReviewsBandSkin } from './sections/reviews-band.js'\nimport type { SiteFooterSkin } from './sections/site-footer.js'\nimport type { AccordionSkin } from './sections/accordion.js'\nimport type { ContactBlockSkin } from './sections/contact-block.js'\nimport type { FAQsSkin } from './sections/faqs.js'\nimport type { PageHeaderSkin } from './sections/page-header.js'\nimport type { PriceGuideSkin } from './sections/price-guide.js'\nimport type { PriceTableSkin } from './sections/price-table.js'\nimport type { ProofStripSkin } from './sections/proof-strip.js'\nimport type { HeroSkin } from './sections/hero.js'\nimport type { ServicesGridSkin } from './sections/services-grid.js'\nimport type { MediaSkin } from './primitives/media.js'\nimport type { BreadcrumbsSkin } from './primitives/breadcrumbs.js'\n\nexport interface BrandlabSkin {\n readonly buttonLink?: ButtonLinkSkin\n readonly textLink?: TextLinkSkin\n readonly phoneLink?: PhoneLinkSkin\n readonly quoteButton?: QuoteButtonSkin\n readonly container?: ContainerSkin\n readonly sectionHeading?: SectionHeadingSkin\n // primitives (3.14.0)\n readonly button?: ButtonSkin\n readonly eyebrow?: EyebrowSkin\n readonly card?: CardSkin\n readonly badge?: BadgeSkin\n readonly chip?: ChipSkin\n readonly stat?: StatSkin\n readonly tickList?: TickListSkin\n readonly linkList?: LinkListSkin\n readonly mediaFrame?: MediaFrameSkin\n readonly siteHeader?: SiteHeaderSkin\n readonly mobileDrawer?: MobileDrawerSkin\n readonly utilityBar?: UtilityBarSkin\n readonly mobileCallBar?: MobileCallBarSkin\n readonly backToTop?: BackToTopSkin\n // form (3.10.0)\n readonly quoteForm?: QuoteFormSkin\n readonly quoteDialog?: QuoteDialogSkin\n readonly photoUpload?: PhotoUploadSkin\n readonly dialog?: DialogSkin\n readonly field?: FieldSkin\n readonly thankYou?: ThankYouSkin\n readonly ratingChip?: RatingChipSkin\n readonly reviewsBand?: ReviewsBandSkin\n readonly ctaBand?: CTABandSkin\n readonly siteFooter?: SiteFooterSkin\n readonly accordion?: AccordionSkin\n readonly faqs?: FAQsSkin\n readonly priceTable?: PriceTableSkin\n readonly priceGuide?: PriceGuideSkin\n readonly proofStrip?: ProofStripSkin\n readonly pageHeader?: PageHeaderSkin\n readonly contactBlock?: ContactBlockSkin\n // hero (3.14.0)\n readonly hero?: HeroSkin\n // 3.14.0\n readonly servicesGrid?: ServicesGridSkin\n readonly media?: MediaSkin\n readonly breadcrumbs?: BreadcrumbsSkin\n}\n"]}
|
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
* photos show as thumbnails with a remove button each.
|
|
7
7
|
*/
|
|
8
8
|
import type { BrandlabContactAttachmentErrorReason, UseBrandlabContactAttachmentsResult } from '../../contact/attachments-client.js';
|
|
9
|
+
import type { RepeatedSlotOf } from '../repeated-slots.js';
|
|
9
10
|
import { type SkinEntry } from '../skin.js';
|
|
10
11
|
export type PhotoUploadSlot = 'field' | 'label' | 'drop' | 'dropIcon' | 'counter' | 'photos' | 'photo' | 'thumb' | 'remove' | 'error';
|
|
11
|
-
|
|
12
|
+
/** Rendered once per chosen photo: styled from the skin stylesheet, never by class (3.14.0). */
|
|
13
|
+
export type PhotoUploadRepeatedSlot = RepeatedSlotOf<'photoUpload'>;
|
|
14
|
+
export type PhotoUploadSkin = SkinEntry<PhotoUploadSlot, never, Record<never, never>, PhotoUploadRepeatedSlot>;
|
|
12
15
|
export interface PhotoUploadProps extends PhotoUploadSkin {
|
|
13
16
|
/** The file input's id. */
|
|
14
17
|
readonly id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"photo-upload.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/form/photo-upload.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,oCAAoC,EACpC,mCAAmC,EACpC,MAAM,qCAAqC,CAAA;AAG5C,OAAO,
|
|
1
|
+
{"version":3,"file":"photo-upload.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/form/photo-upload.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,oCAAoC,EACpC,mCAAmC,EACpC,MAAM,qCAAqC,CAAA;AAG5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AAG/D,MAAM,MAAM,eAAe,GACvB,OAAO,GACP,OAAO,GACP,MAAM,GACN,UAAU,GACV,SAAS,GACT,QAAQ,GACR,OAAO,GACP,OAAO,GACP,QAAQ,GACR,OAAO,CAAA;AACX,gGAAgG;AAChG,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC,aAAa,CAAC,CAAA;AACnE,MAAM,MAAM,eAAe,GAAG,SAAS,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,uBAAuB,CAAC,CAAA;AAE9G,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,6GAA6G;IAC7G,QAAQ,CAAC,WAAW,EAAE,mCAAmC,CAAA;IACzD,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,uFAAuF;IACvF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,qFAAqF;IACrF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,oCAAoC,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;IACnG,kGAAkG;IAClG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,KAAK,EACL,WAAW,EACX,OAAO,EACP,WAAW,EACX,MAAkB,EAClB,aAAa,EACb,KAAK,EACL,QAAgB,EAChB,QAAgB,EAChB,OAAO,GACR,EAAE,gBAAgB,2CAgElB"}
|
|
@@ -3,7 +3,7 @@ import { createElement as _createElement } from "react";
|
|
|
3
3
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { HeadlessStatus } from '../../ui.js';
|
|
5
5
|
import { Icon } from '../icons.js';
|
|
6
|
-
import { slot } from '../skin.js';
|
|
6
|
+
import { repeatedSlot, slot } from '../skin.js';
|
|
7
7
|
import { fillCopy } from './copy.js';
|
|
8
8
|
export function PhotoUpload({ id, label, attachments, counter, removeLabel, accept = 'image/*', errorMessages, error, required = false, disabled = false, classes, }) {
|
|
9
9
|
const counterId = `${id}-count`;
|
|
@@ -12,8 +12,8 @@ export function PhotoUpload({ id, label, attachments, counter, removeLabel, acce
|
|
|
12
12
|
const refused = reason && errorMessages ? fillCopy(errorMessages[reason], { max: attachments.maxImages }) : attachments.errorMessage;
|
|
13
13
|
const message = refused ?? error;
|
|
14
14
|
const state = attachments.isProcessing ? 'busy' : attachments.isDragging ? 'dragging' : 'idle';
|
|
15
|
-
return (_jsxs("div", { "data-bl": "photo-upload", ...slot(classes, 'field'), children: [_jsxs("div", { ...slot(classes, 'drop'), "data-state": state, "data-disabled": disabled ? 'true' : undefined, onDragOver: disabled ? undefined : attachments.handleDragOver, onDragLeave: disabled ? undefined : attachments.handleDragLeave, onDrop: disabled ? undefined : (event) => void attachments.handleDrop(event), children: [_jsx("input", { id: id, type: "file", accept: accept, multiple: true, disabled: disabled, "aria-required": required ? true : undefined, "aria-invalid": message ? true : undefined, "aria-describedby": [counterId, message ? errorId : undefined].filter(Boolean).join(' '), "data-bl-visually-hidden": "", onChange: (event) => void attachments.handleImageChange(event) }), _jsxs("label", { ...slot(classes, 'label'), htmlFor: id, children: [_jsx("span", { ...slot(classes, 'dropIcon'), children: _jsx(Icon, { name: "camera" }) }), _jsx("span", { children: label })] }), _jsx(HeadlessStatus, { ...slot(classes, 'counter'), id: counterId, children: fillCopy(counter, { count: attachments.images.length, max: attachments.maxImages }) })] }), attachments.images.length > 0 ? (_jsx("ul", { ...slot(classes, 'photos'), children: attachments.images.map((image, index) => (_createElement("li", { ...
|
|
16
|
-
_jsx("img", { ...
|
|
17
|
-
_jsxs("button", { ...
|
|
15
|
+
return (_jsxs("div", { "data-bl": "photo-upload", ...slot(classes, 'field'), children: [_jsxs("div", { ...slot(classes, 'drop'), "data-state": state, "data-disabled": disabled ? 'true' : undefined, onDragOver: disabled ? undefined : attachments.handleDragOver, onDragLeave: disabled ? undefined : attachments.handleDragLeave, onDrop: disabled ? undefined : (event) => void attachments.handleDrop(event), children: [_jsx("input", { id: id, type: "file", accept: accept, multiple: true, disabled: disabled, "aria-required": required ? true : undefined, "aria-invalid": message ? true : undefined, "aria-describedby": [counterId, message ? errorId : undefined].filter(Boolean).join(' '), "data-bl-visually-hidden": "", onChange: (event) => void attachments.handleImageChange(event) }), _jsxs("label", { ...slot(classes, 'label'), htmlFor: id, children: [_jsx("span", { ...slot(classes, 'dropIcon'), children: _jsx(Icon, { name: "camera" }) }), _jsx("span", { children: label })] }), _jsx(HeadlessStatus, { ...slot(classes, 'counter'), id: counterId, children: fillCopy(counter, { count: attachments.images.length, max: attachments.maxImages }) })] }), attachments.images.length > 0 ? (_jsx("ul", { ...slot(classes, 'photos'), children: attachments.images.map((image, index) => (_createElement("li", { ...repeatedSlot('photo'), key: image.preview },
|
|
16
|
+
_jsx("img", { ...repeatedSlot('thumb'), src: image.preview, alt: "", width: 64, height: 64 }),
|
|
17
|
+
_jsxs("button", { ...repeatedSlot('remove'), type: "button", disabled: disabled, onClick: () => attachments.removeImage(index), children: [_jsx(Icon, { name: "close" }), _jsx("span", { "data-bl-visually-hidden": "", children: fillCopy(removeLabel, { number: index + 1 }) })] })))) })) : null, message ? (_jsx("div", { ...slot(classes, 'error'), id: errorId, role: "alert", children: message })) : null] }));
|
|
18
18
|
}
|
|
19
19
|
//# sourceMappingURL=photo-upload.js.map
|