astro 4.0.8 → 4.1.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.
Files changed (50) hide show
  1. package/astro-jsx.d.ts +10 -1
  2. package/config.d.ts +2 -1
  3. package/config.mjs +2 -2
  4. package/dist/@types/astro.d.ts +58 -15
  5. package/dist/assets/services/sharp.d.ts +7 -1
  6. package/dist/assets/services/sharp.js +6 -2
  7. package/dist/assets/utils/transformToPath.js +1 -1
  8. package/dist/assets/vite-plugin-assets.js +2 -2
  9. package/dist/cli/add/index.js +4 -2
  10. package/dist/cli/check/index.js +2 -0
  11. package/dist/cli/flags.js +1 -1
  12. package/dist/cli/index.js +0 -3
  13. package/dist/cli/preview/index.js +3 -0
  14. package/dist/core/build/index.js +2 -0
  15. package/dist/core/config/config.js +2 -2
  16. package/dist/core/config/schema.d.ts +26 -26
  17. package/dist/core/config/schema.js +3 -3
  18. package/dist/core/constants.js +1 -1
  19. package/dist/core/cookies/cookies.d.ts +7 -3
  20. package/dist/core/cookies/cookies.js +8 -8
  21. package/dist/core/cookies/index.d.ts +1 -0
  22. package/dist/core/dev/container.js +2 -2
  23. package/dist/core/dev/dev.js +3 -1
  24. package/dist/core/errors/dev/utils.js +5 -2
  25. package/dist/core/errors/dev/vite.d.ts +1 -1
  26. package/dist/core/errors/overlay.js +2 -2
  27. package/dist/core/messages.js +2 -2
  28. package/dist/core/preview/index.js +9 -0
  29. package/dist/core/render/result.js +1 -0
  30. package/dist/core/routing/manifest/create.js +1 -1
  31. package/dist/core/sync/index.js +2 -0
  32. package/dist/core/util.d.ts +4 -0
  33. package/dist/core/util.js +6 -0
  34. package/dist/i18n/index.d.ts +1 -1
  35. package/dist/i18n/index.js +6 -3
  36. package/dist/i18n/vite-plugin-i18n.js +1 -1
  37. package/dist/prefetch/index.js +11 -1
  38. package/dist/runtime/client/dev-overlay/overlay.js +8 -2
  39. package/dist/runtime/client/dev-overlay/plugins/audit/a11y.js +126 -0
  40. package/dist/runtime/client/visible.js +6 -2
  41. package/dist/runtime/client/visible.prebuilt.d.ts +1 -1
  42. package/dist/runtime/client/visible.prebuilt.js +1 -1
  43. package/dist/runtime/server/render/common.js +9 -0
  44. package/dist/runtime/server/render/component.js +9 -0
  45. package/dist/runtime/server/render/instruction.d.ts +11 -1
  46. package/dist/transitions/router.js +9 -3
  47. package/dist/vite-plugin-astro-server/base.js +6 -1
  48. package/dist/vite-plugin-astro-server/error.js +4 -2
  49. package/dist/vite-plugin-dev-overlay/vite-plugin-dev-overlay.js +8 -0
  50. package/package.json +4 -1
@@ -62,7 +62,7 @@ class AstroCookies {
62
62
  * @param key The cookie to get.
63
63
  * @returns An object containing the cookie value as well as convenience methods for converting its value.
64
64
  */
65
- get(key) {
65
+ get(key, options = void 0) {
66
66
  if (this.#outgoing?.has(key)) {
67
67
  let [serializedValue, , isSetValue] = this.#outgoing.get(key);
68
68
  if (isSetValue) {
@@ -71,7 +71,7 @@ class AstroCookies {
71
71
  return void 0;
72
72
  }
73
73
  }
74
- const values = this.#ensureParsed();
74
+ const values = this.#ensureParsed(options);
75
75
  if (key in values) {
76
76
  const value = values[key];
77
77
  return new AstroCookie(value);
@@ -83,12 +83,12 @@ class AstroCookies {
83
83
  * @param key The cookie to check for.
84
84
  * @returns
85
85
  */
86
- has(key) {
86
+ has(key, options = void 0) {
87
87
  if (this.#outgoing?.has(key)) {
88
88
  let [, , isSetValue] = this.#outgoing.get(key);
89
89
  return isSetValue;
90
90
  }
91
- const values = this.#ensureParsed();
91
+ const values = this.#ensureParsed(options);
92
92
  return !!values[key];
93
93
  }
94
94
  /**
@@ -140,9 +140,9 @@ class AstroCookies {
140
140
  yield value[1];
141
141
  }
142
142
  }
143
- #ensureParsed() {
143
+ #ensureParsed(options = void 0) {
144
144
  if (!this.#requestValues) {
145
- this.#parse();
145
+ this.#parse(options);
146
146
  }
147
147
  if (!this.#requestValues) {
148
148
  this.#requestValues = {};
@@ -155,12 +155,12 @@ class AstroCookies {
155
155
  }
156
156
  return this.#outgoing;
157
157
  }
158
- #parse() {
158
+ #parse(options = void 0) {
159
159
  const raw = this.#request.headers.get("cookie");
160
160
  if (!raw) {
161
161
  return;
162
162
  }
163
- this.#requestValues = parse(raw);
163
+ this.#requestValues = parse(raw, options);
164
164
  }
165
165
  }
166
166
  export {
@@ -1,2 +1,3 @@
1
1
  export { AstroCookies } from './cookies.js';
2
2
  export { attachCookiesToResponse, getSetCookiesFromResponse, responseHasCookies, } from './response.js';
3
+ export type { AstroCookieSetOptions, AstroCookieGetOptions } from './cookies.js';
@@ -26,9 +26,9 @@ async function createContainer({
26
26
  settings = injectImageEndpoint(settings, "dev");
27
27
  const {
28
28
  base,
29
- server: { host, headers, open: shouldOpen }
29
+ server: { host, headers, open: serverOpen }
30
30
  } = settings.config;
31
- const open = shouldOpen ? base : false;
31
+ const open = typeof serverOpen == "string" ? serverOpen : serverOpen ? base : false;
32
32
  const rendererClientEntries = settings.renderers.map((r) => r.clientEntrypoint).filter(Boolean);
33
33
  const viteConfig = await createVite(
34
34
  {
@@ -6,7 +6,9 @@ import { telemetry } from "../../events/index.js";
6
6
  import * as msg from "../messages.js";
7
7
  import { startContainer } from "./container.js";
8
8
  import { createContainerWithAutomaticRestart } from "./restart.js";
9
+ import { ensureProcessNodeEnv } from "../util.js";
9
10
  async function dev(inlineConfig) {
11
+ ensureProcessNodeEnv("development");
10
12
  const devStart = performance.now();
11
13
  await telemetry.record([]);
12
14
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
@@ -21,7 +23,7 @@ async function dev(inlineConfig) {
21
23
  base: restart.container.settings.config.base
22
24
  })
23
25
  );
24
- const currentVersion = "4.0.8";
26
+ const currentVersion = "4.1.0";
25
27
  if (currentVersion.includes("-")) {
26
28
  logger.warn("SKIP_FORMAT", msg.prerelease({ currentVersion }));
27
29
  }
@@ -15,7 +15,7 @@ function collectErrorMetadata(e, rootFolder) {
15
15
  err.forEach((error) => {
16
16
  if (e.stack) {
17
17
  const stackInfo = collectInfoFromStacktrace(e);
18
- error.stack = stackInfo.stack;
18
+ error.stack = stripAnsi(stackInfo.stack);
19
19
  error.loc = stackInfo.loc;
20
20
  error.plugin = stackInfo.plugin;
21
21
  error.pluginCode = stackInfo.pluginCode;
@@ -30,7 +30,7 @@ function collectErrorMetadata(e, rootFolder) {
30
30
  const fileContents = fs.readFileSync(error.loc.file, "utf8");
31
31
  if (!error.frame) {
32
32
  const frame = codeFrame(fileContents, error.loc);
33
- error.frame = frame;
33
+ error.frame = stripAnsi(frame);
34
34
  }
35
35
  if (!error.fullCode) {
36
36
  error.fullCode = fileContents;
@@ -39,6 +39,9 @@ function collectErrorMetadata(e, rootFolder) {
39
39
  }
40
40
  }
41
41
  error.hint = generateHint(e);
42
+ if (error.message) {
43
+ error.message = stripAnsi(error.message);
44
+ }
42
45
  });
43
46
  if (!AggregateError.is(e) && Array.isArray(e.errors)) {
44
47
  e.errors.forEach((buildError, i) => {
@@ -16,7 +16,7 @@ export interface AstroErrorPayload {
16
16
  hint?: string;
17
17
  docslink?: string;
18
18
  highlightedCode?: string;
19
- loc: {
19
+ loc?: {
20
20
  file?: string;
21
21
  line?: number;
22
22
  column?: number;
@@ -621,7 +621,7 @@ class ErrorOverlay extends HTMLElement {
621
621
  docslink.appendChild(this.createLink(`See Docs Reference${openNewWindowIcon}`, err.docslink));
622
622
  }
623
623
  const code = this.root.querySelector("#code");
624
- if (code && err.loc.file) {
624
+ if (code && err.loc?.file) {
625
625
  code.style.display = "block";
626
626
  const codeHeader = code.querySelector("#code header");
627
627
  const codeContent = code.querySelector("#code-content");
@@ -647,7 +647,7 @@ class ErrorOverlay extends HTMLElement {
647
647
  if (errorLine.parentElement?.parentElement) {
648
648
  errorLine.parentElement.parentElement.scrollTop = errorLine.offsetTop - errorLine.parentElement.parentElement.offsetTop - 8;
649
649
  }
650
- if (err.loc.column) {
650
+ if (err.loc?.column) {
651
651
  errorLine.insertAdjacentHTML(
652
652
  "afterend",
653
653
  `
@@ -36,7 +36,7 @@ function serverStart({
36
36
  host,
37
37
  base
38
38
  }) {
39
- const version = "4.0.8";
39
+ const version = "4.1.0";
40
40
  const localPrefix = `${dim("\u2503")} Local `;
41
41
  const networkPrefix = `${dim("\u2503")} Network `;
42
42
  const emptyPrefix = " ".repeat(11);
@@ -258,7 +258,7 @@ function printHelp({
258
258
  message.push(
259
259
  linebreak(),
260
260
  ` ${bgGreen(black(` ${commandName} `))} ${green(
261
- `v${"4.0.8"}`
261
+ `v${"4.1.0"}`
262
262
  )} ${headline}`
263
263
  );
264
264
  }
@@ -1,3 +1,4 @@
1
+ import fs from "node:fs";
1
2
  import { createRequire } from "node:module";
2
3
  import { fileURLToPath, pathToFileURL } from "node:url";
3
4
  import { AstroIntegrationLogger } from "../../core/logger/core.js";
@@ -9,7 +10,9 @@ import { createNodeLogger } from "../config/logging.js";
9
10
  import { createSettings } from "../config/settings.js";
10
11
  import createStaticPreviewServer from "./static-preview-server.js";
11
12
  import { getResolvedHostForHttpServer } from "./util.js";
13
+ import { ensureProcessNodeEnv } from "../util.js";
12
14
  async function preview(inlineConfig) {
15
+ ensureProcessNodeEnv("production");
13
16
  const logger = createNodeLogger(inlineConfig);
14
17
  const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, "preview");
15
18
  telemetry.record(eventCliSession("preview", userConfig));
@@ -21,6 +24,12 @@ async function preview(inlineConfig) {
21
24
  });
22
25
  await runHookConfigDone({ settings, logger });
23
26
  if (settings.config.output === "static") {
27
+ if (!fs.existsSync(settings.config.outDir)) {
28
+ const outDirPath = fileURLToPath(settings.config.outDir);
29
+ throw new Error(
30
+ `[preview] The output directory ${outDirPath} does not exist. Did you run \`astro build\`?`
31
+ );
32
+ }
24
33
  const server2 = await createStaticPreviewServer(settings, logger);
25
34
  return server2;
26
35
  }
@@ -198,6 +198,7 @@ function createResult(args) {
198
198
  response,
199
199
  _metadata: {
200
200
  hasHydrationScript: false,
201
+ rendererSpecificHydrationScripts: /* @__PURE__ */ new Set(),
201
202
  hasRenderedHead: false,
202
203
  hasDirectives: /* @__PURE__ */ new Set(),
203
204
  headInTree: false,
@@ -224,7 +224,7 @@ function createRouteManifest({ settings, cwd, fsMod }, logger) {
224
224
  } else {
225
225
  components.push(item.file);
226
226
  const component = item.file;
227
- const trailingSlash = item.isPage ? settings.config.trailingSlash : "never";
227
+ const { trailingSlash } = settings.config;
228
228
  const pattern = getPattern(segments, settings.config, trailingSlash);
229
229
  const generate = getRouteGenerator(segments, trailingSlash);
230
230
  const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
@@ -15,7 +15,9 @@ import { createNodeLogger } from "../config/logging.js";
15
15
  import { createSettings } from "../config/settings.js";
16
16
  import { createVite } from "../create-vite.js";
17
17
  import { AstroError, AstroErrorData, createSafeError, isAstroError } from "../errors/index.js";
18
+ import { ensureProcessNodeEnv } from "../util.js";
18
19
  async function sync(inlineConfig, options) {
20
+ ensureProcessNodeEnv("production");
19
21
  const logger = createNodeLogger(inlineConfig);
20
22
  const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, "sync");
21
23
  telemetry.record(eventCliSession("sync", userConfig));
@@ -50,3 +50,7 @@ export declare function resolveJsToTs(filePath: string): string;
50
50
  * Resolve the hydration paths so that it can be imported in the client
51
51
  */
52
52
  export declare function resolvePath(specifier: string, importer: string): string;
53
+ /**
54
+ * Set a default NODE_ENV so Vite doesn't set an incorrect default when loading the Astro config
55
+ */
56
+ export declare function ensureProcessNodeEnv(defaultNodeEnv: string): void;
package/dist/core/util.js CHANGED
@@ -174,11 +174,17 @@ function resolvePath(specifier, importer) {
174
174
  return specifier;
175
175
  }
176
176
  }
177
+ function ensureProcessNodeEnv(defaultNodeEnv) {
178
+ if (!process.env.NODE_ENV) {
179
+ process.env.NODE_ENV = defaultNodeEnv;
180
+ }
181
+ }
177
182
  export {
178
183
  NULL_BYTE_PLACEHOLDER,
179
184
  VALID_ID_PREFIX,
180
185
  arraify,
181
186
  emoji,
187
+ ensureProcessNodeEnv,
182
188
  getOutputFilename,
183
189
  isEndpoint,
184
190
  isMarkdownFile,
@@ -53,7 +53,7 @@ export declare function getPathByLocale(locale: string, locales: Locales): strin
53
53
  /**
54
54
  * An utility function that retrieves the preferred locale that correspond to a path.
55
55
  *
56
- * @param locale
56
+ * @param path
57
57
  * @param locales
58
58
  */
59
59
  export declare function getLocaleByPath(path: string, locales: Locales): string | undefined;
@@ -99,10 +99,13 @@ function getPathByLocale(locale, locales) {
99
99
  function getLocaleByPath(path, locales) {
100
100
  for (const locale of locales) {
101
101
  if (typeof locale !== "string") {
102
- const code = locale.codes.at(0);
103
- return code;
102
+ if (locale.path === path) {
103
+ const code = locale.codes.at(0);
104
+ return code;
105
+ }
106
+ } else if (locale === path) {
107
+ return locale;
104
108
  }
105
- 1;
106
109
  }
107
110
  return void 0;
108
111
  }
@@ -54,7 +54,7 @@ function astroInternationalization({
54
54
  export const getAbsoluteLocaleUrlList = (path = "", opts) => _getLocaleAbsoluteUrlList({ base, path, trailingSlash, format, site, ...i18n, ...opts });
55
55
 
56
56
  export const getPathByLocale = (locale) => _getPathByLocale(locale, i18n.locales);
57
- export const getLocaleByPath = (locale) => _getLocaleByPath(locale, i18n.locales);
57
+ export const getLocaleByPath = (path) => _getLocaleByPath(path, i18n.locales);
58
58
  `;
59
59
  }
60
60
  }
@@ -17,6 +17,7 @@ function init(defaultOpts) {
17
17
  initTapStrategy();
18
18
  initHoverStrategy();
19
19
  initViewportStrategy();
20
+ initLoadStrategy();
20
21
  }
21
22
  function initTapStrategy() {
22
23
  for (const event of ["touchstart", "mousedown"]) {
@@ -111,6 +112,15 @@ function createViewportIntersectionObserver() {
111
112
  }
112
113
  });
113
114
  }
115
+ function initLoadStrategy() {
116
+ onPageLoad(() => {
117
+ for (const anchor of document.getElementsByTagName("a")) {
118
+ if (elMatchesStrategy(anchor, "load")) {
119
+ prefetch(anchor.href, { with: "link" });
120
+ }
121
+ }
122
+ });
123
+ }
114
124
  function prefetch(url, opts) {
115
125
  const ignoreSlowConnection = opts?.ignoreSlowConnection ?? false;
116
126
  if (!canPrefetchUrl(url, ignoreSlowConnection))
@@ -163,7 +173,7 @@ function elMatchesStrategy(el, strategy) {
163
173
  function isSlowConnection() {
164
174
  if ("connection" in navigator) {
165
175
  const conn = navigator.connection;
166
- return conn.saveData || /(2|3)g/.test(conn.effectiveType);
176
+ return conn.saveData || /2g/.test(conn.effectiveType);
167
177
  }
168
178
  return false;
169
179
  }
@@ -3,6 +3,7 @@ import { getIconElement, isDefinedIcon } from "./ui-library/icons.js";
3
3
  const WS_EVENT_NAME = "astro-dev-toolbar";
4
4
  const WS_EVENT_NAME_DEPRECATED = "astro-dev-overlay";
5
5
  const HOVER_DELAY = 2 * 1e3;
6
+ const DEVBAR_HITBOX_ABOVE = 42;
6
7
  class AstroDevOverlay extends HTMLElement {
7
8
  shadowRoot;
8
9
  delayedHideTimeout;
@@ -62,7 +63,7 @@ class AstroDevOverlay extends HTMLElement {
62
63
  pointer-events: auto;
63
64
  }
64
65
  #dev-bar-hitbox-above {
65
- height: 42px;
66
+ height: ${DEVBAR_HITBOX_ABOVE}px;
66
67
  }
67
68
  #dev-bar-hitbox-below {
68
69
  height: 16px;
@@ -131,7 +132,7 @@ class AstroDevOverlay extends HTMLElement {
131
132
  border-radius: 4px;
132
133
  padding: 4px 8px;
133
134
  position: absolute;
134
- top: 4px;
135
+ top: ${4 - DEVBAR_HITBOX_ABOVE}px;
135
136
  font-size: 14px;
136
137
  opacity: 0;
137
138
  transition: opacity 0.2s ease-in-out 0s;
@@ -423,16 +424,21 @@ class AstroDevOverlay extends HTMLElement {
423
424
  setOverlayVisible(newStatus) {
424
425
  const barContainer = this.shadowRoot.querySelector("#bar-container");
425
426
  const devBar = this.shadowRoot.querySelector("#dev-bar");
427
+ const devBarHitboxAbove = this.shadowRoot.querySelector("#dev-bar-hitbox-above");
426
428
  if (newStatus === true) {
427
429
  this.devOverlay?.removeAttribute("data-hidden");
428
430
  barContainer?.removeAttribute("inert");
429
431
  devBar?.removeAttribute("tabindex");
432
+ if (devBarHitboxAbove)
433
+ devBarHitboxAbove.style.height = "0";
430
434
  return;
431
435
  }
432
436
  if (newStatus === false) {
433
437
  this.devOverlay?.setAttribute("data-hidden", "");
434
438
  barContainer?.setAttribute("inert", "");
435
439
  devBar?.setAttribute("tabindex", "0");
440
+ if (devBarHitboxAbove)
441
+ devBarHitboxAbove.style.height = `${DEVBAR_HITBOX_ABOVE}px`;
436
442
  return;
437
443
  }
438
444
  }
@@ -22,6 +22,8 @@
22
22
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
23
  * SOFTWARE.
24
24
  */
25
+ import { aria, roles } from "aria-query";
26
+ import { AXObjectRoles, elementAXObjects } from "axobject-query";
25
27
  const a11y_required_attributes = {
26
28
  a: ["href"],
27
29
  area: ["alt", "aria-label", "aria-labelledby"],
@@ -413,6 +415,58 @@ const a11y = [
413
415
  message: "This will move elements out of the expected tab order, creating a confusing experience for keyboard users.",
414
416
  selector: '[tabindex]:not([tabindex="-1"]):not([tabindex="0"])'
415
417
  },
418
+ {
419
+ code: "a11y-role-has-required-aria-props",
420
+ title: "Missing attributes required for ARIA role",
421
+ message: (element) => {
422
+ const { __astro_role: role, __astro_missing_attributes: required } = element;
423
+ return `${element.localName} element is missing required attributes for its role (${role}): ${required.join(", ")}`;
424
+ },
425
+ selector: "*",
426
+ match(element) {
427
+ const role = getRole(element);
428
+ if (!role)
429
+ return false;
430
+ if (is_semantic_role_element(role, element.localName, getAttributeObject(element))) {
431
+ return;
432
+ }
433
+ const { requiredProps } = roles.get(role);
434
+ const required_role_props = Object.keys(requiredProps);
435
+ const missingProps = required_role_props.filter((prop) => !element.hasAttribute(prop));
436
+ if (missingProps.length > 0) {
437
+ element.__astro_role = role;
438
+ element.__astro_missing_attributes = missingProps;
439
+ return true;
440
+ }
441
+ }
442
+ },
443
+ {
444
+ code: "a11y-role-supports-aria-props",
445
+ title: "Unsupported ARIA attribute",
446
+ message: (element) => {
447
+ const { __astro_role: role, __astro_unsupported_attributes: unsupported } = element;
448
+ return `${element.localName} element has ARIA attributes that are not supported by its role (${role}): ${unsupported.join(
449
+ ", "
450
+ )}`;
451
+ },
452
+ selector: "*",
453
+ match(element) {
454
+ const role = getRole(element);
455
+ if (!role)
456
+ return false;
457
+ const { props } = roles.get(role);
458
+ const attributes = getAttributeObject(element);
459
+ const unsupportedAttributes = aria.keys().filter((attribute) => !(attribute in props));
460
+ const invalidAttributes = Object.keys(attributes).filter(
461
+ (key) => key.startsWith("aria-") && unsupportedAttributes.includes(key)
462
+ );
463
+ if (invalidAttributes.length > 0) {
464
+ element.__astro_role = role;
465
+ element.__astro_unsupported_attributes = invalidAttributes;
466
+ return true;
467
+ }
468
+ }
469
+ },
416
470
  {
417
471
  code: "a11y-structure",
418
472
  title: "Invalid DOM structure",
@@ -447,6 +501,16 @@ const a11y = [
447
501
  }
448
502
  }
449
503
  ];
504
+ const a11y_labelable = [
505
+ "button",
506
+ "input",
507
+ "keygen",
508
+ "meter",
509
+ "output",
510
+ "progress",
511
+ "select",
512
+ "textarea"
513
+ ];
450
514
  const a11y_non_interactive_element_to_interactive_role_exceptions = {
451
515
  ul: ["listbox", "menu", "menubar", "radiogroup", "tablist", "tree", "treegrid"],
452
516
  ol: ["listbox", "menu", "menubar", "radiogroup", "tablist", "tree", "treegrid"],
@@ -455,6 +519,68 @@ const a11y_non_interactive_element_to_interactive_role_exceptions = {
455
519
  td: ["gridcell"],
456
520
  fieldset: ["radiogroup", "presentation"]
457
521
  };
522
+ const combobox_if_list = ["email", "search", "tel", "text", "url"];
523
+ function input_implicit_role(attributes) {
524
+ if (!("type" in attributes))
525
+ return;
526
+ const { type, list } = attributes;
527
+ if (!type)
528
+ return;
529
+ if (list && combobox_if_list.includes(type)) {
530
+ return "combobox";
531
+ }
532
+ return input_type_to_implicit_role.get(type);
533
+ }
534
+ function menuitem_implicit_role(attributes) {
535
+ if (!("type" in attributes))
536
+ return;
537
+ const { type } = attributes;
538
+ if (!type)
539
+ return;
540
+ return menuitem_type_to_implicit_role.get(type);
541
+ }
542
+ function getRole(element) {
543
+ if (element.hasAttribute("role")) {
544
+ return element.getAttribute("role");
545
+ }
546
+ return getImplicitRole(element);
547
+ }
548
+ function getImplicitRole(element) {
549
+ const name = element.localName;
550
+ const attrs = getAttributeObject(element);
551
+ if (name === "menuitem") {
552
+ return menuitem_implicit_role(attrs);
553
+ } else if (name === "input") {
554
+ return input_implicit_role(attrs);
555
+ } else {
556
+ return a11y_implicit_semantics.get(name);
557
+ }
558
+ }
559
+ function getAttributeObject(element) {
560
+ let obj = {};
561
+ for (let i = 0; i < element.attributes.length; i++) {
562
+ const attribute = element.attributes.item(i);
563
+ obj[attribute.name] = attribute.value;
564
+ }
565
+ return obj;
566
+ }
567
+ function is_semantic_role_element(role, tag_name, attributes) {
568
+ for (const [schema, ax_object] of elementAXObjects.entries()) {
569
+ if (schema.name === tag_name && (!schema.attributes || schema.attributes.every((attr) => attributes[attr.name] === attr.value))) {
570
+ for (const name of ax_object) {
571
+ const axRoles = AXObjectRoles.get(name);
572
+ if (axRoles) {
573
+ for (const { name: _name } of axRoles) {
574
+ if (_name === role) {
575
+ return true;
576
+ }
577
+ }
578
+ }
579
+ }
580
+ }
581
+ }
582
+ return false;
583
+ }
458
584
  export {
459
585
  a11y
460
586
  };
@@ -1,8 +1,12 @@
1
- const visibleDirective = (load, _options, el) => {
1
+ const visibleDirective = (load, options, el) => {
2
2
  const cb = async () => {
3
3
  const hydrate = await load();
4
4
  await hydrate();
5
5
  };
6
+ const rawOptions = typeof options.value === "object" ? options.value : void 0;
7
+ const ioOptions = {
8
+ rootMargin: rawOptions?.rootMargin
9
+ };
6
10
  const io = new IntersectionObserver((entries) => {
7
11
  for (const entry of entries) {
8
12
  if (!entry.isIntersecting)
@@ -11,7 +15,7 @@ const visibleDirective = (load, _options, el) => {
11
15
  cb();
12
16
  break;
13
17
  }
14
- });
18
+ }, ioOptions);
15
19
  for (const child of el.children) {
16
20
  io.observe(child);
17
21
  }
@@ -3,5 +3,5 @@
3
3
  * Do not edit this directly, but instead edit that file and rerun the prebuild
4
4
  * to generate this file.
5
5
  */
6
- declare const _default: "(()=>{var r=(i,c,s)=>{let n=async()=>{await(await i())()},t=new IntersectionObserver(e=>{for(let o of e)if(o.isIntersecting){t.disconnect(),n();break}});for(let e of s.children)t.observe(e)};(self.Astro||(self.Astro={})).visible=r;window.dispatchEvent(new Event(\"astro:visible\"));})();";
6
+ declare const _default: "(()=>{var l=(s,i,o)=>{let r=async()=>{await(await s())()},t=typeof i.value==\"object\"?i.value:void 0,c={rootMargin:t==null?void 0:t.rootMargin},n=new IntersectionObserver(e=>{for(let a of e)if(a.isIntersecting){n.disconnect(),r();break}},c);for(let e of o.children)n.observe(e)};(self.Astro||(self.Astro={})).visible=l;window.dispatchEvent(new Event(\"astro:visible\"));})();";
7
7
  export default _default;
@@ -1,4 +1,4 @@
1
- var visible_prebuilt_default = `(()=>{var r=(i,c,s)=>{let n=async()=>{await(await i())()},t=new IntersectionObserver(e=>{for(let o of e)if(o.isIntersecting){t.disconnect(),n();break}});for(let e of s.children)t.observe(e)};(self.Astro||(self.Astro={})).visible=r;window.dispatchEvent(new Event("astro:visible"));})();`;
1
+ var visible_prebuilt_default = `(()=>{var l=(s,i,o)=>{let r=async()=>{await(await s())()},t=typeof i.value=="object"?i.value:void 0,c={rootMargin:t==null?void 0:t.rootMargin},n=new IntersectionObserver(e=>{for(let a of e)if(a.isIntersecting){n.disconnect(),r();break}},c);for(let e of o.children)n.observe(e)};(self.Astro||(self.Astro={})).visible=l;window.dispatchEvent(new Event("astro:visible"));})();`;
2
2
  export {
3
3
  visible_prebuilt_default as default
4
4
  };
@@ -39,6 +39,15 @@ function stringifyChunk(result, chunk) {
39
39
  }
40
40
  return renderAllHeadContent(result);
41
41
  }
42
+ case "renderer-hydration-script": {
43
+ const { rendererSpecificHydrationScripts } = result._metadata;
44
+ const { rendererName } = instruction;
45
+ if (!rendererSpecificHydrationScripts.has(rendererName)) {
46
+ rendererSpecificHydrationScripts.add(rendererName);
47
+ return instruction.render();
48
+ }
49
+ return "";
50
+ }
42
51
  default: {
43
52
  throw new Error(`Unknown chunk type: ${chunk.type}`);
44
53
  }
@@ -291,6 +291,15 @@ ${serializeProps(
291
291
  }
292
292
  }
293
293
  destination.write(createRenderInstruction({ type: "directive", hydration }));
294
+ if (hydration.directive !== "only" && renderer?.ssr.renderHydrationScript) {
295
+ destination.write(
296
+ createRenderInstruction({
297
+ type: "renderer-hydration-script",
298
+ rendererName: renderer.name,
299
+ render: renderer.ssr.renderHydrationScript
300
+ })
301
+ );
302
+ }
294
303
  destination.write(markHTMLString(renderElement("astro-island", island, false)));
295
304
  }
296
305
  };
@@ -6,11 +6,21 @@ export type RenderDirectiveInstruction = {
6
6
  export type RenderHeadInstruction = {
7
7
  type: 'head';
8
8
  };
9
+ /**
10
+ * Render a renderer-specific hydration script before the first component of that
11
+ * framework
12
+ */
13
+ export type RendererHydrationScriptInstruction = {
14
+ type: 'renderer-hydration-script';
15
+ rendererName: string;
16
+ render: () => string;
17
+ };
9
18
  export type MaybeRenderHeadInstruction = {
10
19
  type: 'maybe-head';
11
20
  };
12
- export type RenderInstruction = RenderDirectiveInstruction | RenderHeadInstruction | MaybeRenderHeadInstruction;
21
+ export type RenderInstruction = RenderDirectiveInstruction | RenderHeadInstruction | MaybeRenderHeadInstruction | RendererHydrationScriptInstruction;
13
22
  export declare function createRenderInstruction(instruction: RenderDirectiveInstruction): RenderDirectiveInstruction;
23
+ export declare function createRenderInstruction(instruction: RendererHydrationScriptInstruction): RendererHydrationScriptInstruction;
14
24
  export declare function createRenderInstruction(instruction: RenderHeadInstruction): RenderHeadInstruction;
15
25
  export declare function createRenderInstruction(instruction: MaybeRenderHeadInstruction): MaybeRenderHeadInstruction;
16
26
  export declare function isRenderInstruction(chunk: any): chunk is RenderInstruction;