@stackone/malachite 2.68.0 → 2.69.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.
@@ -1 +1 @@
1
- {"version":3,"file":"dateMath.js","sources":["../../src/components/dateMath.ts"],"sourcesContent":["export type DatePickerTimeZone = 'local' | 'utc';\n\nexport type DatePickerPrecision = 'day' | 'minute' | 'second';\n\nexport type WeekStart = 'monday' | 'sunday';\n\nexport interface DayKey {\n year: number;\n month: number;\n day: number;\n}\n\nexport interface MonthKey {\n year: number;\n month: number;\n}\n\nexport interface DateTimeParts extends DayKey {\n hours: number;\n minutes: number;\n seconds: number;\n}\n\nexport interface DateRange {\n start: Date;\n end: Date;\n}\n\nconst MONTHS_SHORT = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n] as const;\n\nconst WEEKDAYS_SHORT = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] as const;\nconst WEEKDAYS_LONG = [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n] as const;\n\nexport const partsOf = (date: Date, zone: DatePickerTimeZone): DateTimeParts =>\n zone === 'utc'\n ? {\n year: date.getUTCFullYear(),\n month: date.getUTCMonth(),\n day: date.getUTCDate(),\n hours: date.getUTCHours(),\n minutes: date.getUTCMinutes(),\n seconds: date.getUTCSeconds(),\n }\n : {\n year: date.getFullYear(),\n month: date.getMonth(),\n day: date.getDate(),\n hours: date.getHours(),\n minutes: date.getMinutes(),\n seconds: date.getSeconds(),\n };\n\n// `Date` reads years 0-99 as 19xx; build 400 years on (same calendar) and move back.\nconst YEAR_SHIFT = 400;\n\nexport const fromParts = (\n { year, month, day, hours = 0, minutes = 0, seconds = 0 }: DayKey & Partial<DateTimeParts>,\n zone: DatePickerTimeZone,\n milliseconds = 0,\n): Date => {\n const shift = year >= 0 && year < 100 ? YEAR_SHIFT : 0;\n if (zone === 'utc') {\n const date = new Date(\n Date.UTC(year + shift, month, day, hours, minutes, seconds, milliseconds),\n );\n if (shift) {\n date.setUTCFullYear(date.getUTCFullYear() - shift);\n }\n return date;\n }\n const date = new Date(year + shift, month, day, hours, minutes, seconds, milliseconds);\n if (shift) {\n date.setFullYear(date.getFullYear() - shift);\n }\n return date;\n};\n\nexport const dayKeyOf = (date: Date, zone: DatePickerTimeZone): DayKey => {\n const { year, month, day } = partsOf(date, zone);\n return { year, month, day };\n};\n\nexport const compareDays = (a: DayKey, b: DayKey): number =>\n a.year - b.year || a.month - b.month || a.day - b.day;\n\nexport const sameDay = (a: DayKey | null | undefined, b: DayKey | null | undefined): boolean =>\n !!a && !!b && compareDays(a, b) === 0;\n\nexport const dayKeyString = ({ year, month, day }: DayKey): string =>\n `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n\nexport const startOfDay = ({ year, month, day }: DayKey, zone: DatePickerTimeZone): Date =>\n fromParts({ year, month, day }, zone);\n\nexport const endOfDay = ({ year, month, day }: DayKey, zone: DatePickerTimeZone): Date =>\n fromParts({ year, month, day, hours: 23, minutes: 59, seconds: 59 }, zone, 999);\n\nexport const addDays = (day: DayKey, amount: number): DayKey =>\n dayKeyOf(fromParts({ year: day.year, month: day.month, day: day.day + amount }, 'utc'), 'utc');\n\nexport const daysInMonth = ({ year, month }: MonthKey): number =>\n dayKeyOf(fromParts({ year, month: month + 1, day: 0 }, 'utc'), 'utc').day;\n\nexport const addMonths = ({ year, month }: MonthKey, amount: number): MonthKey => {\n const total = year * 12 + month + amount;\n return { year: Math.floor(total / 12), month: ((total % 12) + 12) % 12 };\n};\n\nexport const addMonthsToDay = (day: DayKey, amount: number): DayKey => {\n const target = addMonths(day, amount);\n return { ...target, day: Math.min(day.day, daysInMonth(target)) };\n};\n\nexport const weekdayOf = (day: DayKey): number => fromParts(day, 'utc').getUTCDay();\n\nconst WEEK_START_INDEX: Record<WeekStart, number> = { sunday: 0, monday: 1 };\n\nexport const weekdayLabels = (weekStart: WeekStart): { short: string; long: string }[] =>\n Array.from({ length: 7 }, (_, index) => {\n const weekday = (index + WEEK_START_INDEX[weekStart]) % 7;\n return { short: WEEKDAYS_SHORT[weekday], long: WEEKDAYS_LONG[weekday] };\n });\n\nexport const monthWeeks = (view: MonthKey, weekStart: WeekStart): DayKey[][] => {\n const first: DayKey = { ...view, day: 1 };\n const lead = (weekdayOf(first) - WEEK_START_INDEX[weekStart] + 7) % 7;\n const cellCount = Math.ceil((lead + daysInMonth(view)) / 7) * 7;\n const start = addDays(first, -lead);\n const weeks: DayKey[][] = [];\n for (let index = 0; index < cellCount; index++) {\n if (index % 7 === 0) {\n weeks.push([]);\n }\n weeks[weeks.length - 1].push(addDays(start, index));\n }\n return weeks;\n};\n\nexport const startOfWeek = (day: DayKey, weekStart: WeekStart): DayKey =>\n addDays(day, -((weekdayOf(day) - WEEK_START_INDEX[weekStart] + 7) % 7));\n\nexport const monthLabel = ({ year, month }: MonthKey): string => `${MONTHS_SHORT[month]} ${year}`;\n\nconst pad = (value: number): string => String(value).padStart(2, '0');\n\nexport const formatTime = (\n parts: Pick<DateTimeParts, 'hours' | 'minutes' | 'seconds'>,\n precision: DatePickerPrecision,\n): string =>\n precision === 'second'\n ? `${pad(parts.hours)}:${pad(parts.minutes)}:${pad(parts.seconds)}`\n : `${pad(parts.hours)}:${pad(parts.minutes)}`;\n\nconst zoneSuffix = (zone: DatePickerTimeZone): string => (zone === 'utc' ? ' UTC' : '');\n\nexport const formatDate = (\n date: Date,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): string => {\n const parts = partsOf(date, zone);\n const day = `${MONTHS_SHORT[parts.month]} ${parts.day} ${parts.year}`;\n return precision === 'day' ? day : `${day}, ${formatTime(parts, precision)}${zoneSuffix(zone)}`;\n};\n\nexport const formatTimeReadout = (\n date: Date | null,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): string =>\n `${date ? formatTime(partsOf(date, zone), precision) : precision === 'second' ? '--:--:--' : '--:--'}${zoneSuffix(zone)}`;\n\n// Lazy, so importing the module has no side effects.\nlet spokenDayFormat: Intl.DateTimeFormat | undefined;\n\nexport const spokenDay = (day: DayKey): string => {\n spokenDayFormat ??= new Intl.DateTimeFormat('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n timeZone: 'UTC',\n });\n return spokenDayFormat.format(fromParts(day, 'utc'));\n};\n\nexport const clampDate = (date: Date, min?: Date, max?: Date): Date => {\n if (min && date.getTime() < min.getTime()) {\n return new Date(min.getTime());\n }\n if (max && date.getTime() > max.getTime()) {\n return new Date(max.getTime());\n }\n return date;\n};\n\nexport const overlapsBounds = (from: Date, to: Date, min?: Date, max?: Date): boolean =>\n (!min || to.getTime() >= min.getTime()) && (!max || from.getTime() <= max.getTime());\n\nconst isValidDate = (value: unknown): value is Date =>\n value instanceof Date && !Number.isNaN(value.getTime());\n\nconst ZONELESS = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{1,3}))?)?)?$/;\n\nexport const toDate = (\n value: Date | string | number | null | undefined,\n zone: DatePickerTimeZone,\n): Date | null => {\n if (value === null || value === undefined || value === '') {\n return null;\n }\n // Without an offset, a string names a wall-clock time in `zone`, not in the browser's.\n const zoneless = typeof value === 'string' ? ZONELESS.exec(value) : null;\n if (zoneless) {\n const [, year, month, day, hours = '0', minutes = '0', seconds = '0', ms = ''] = zoneless;\n const parts = {\n year: Number(year),\n month: Number(month) - 1,\n day: Number(day),\n hours: Number(hours),\n minutes: Number(minutes),\n seconds: Number(seconds),\n };\n if (parts.hours > 23 || parts.minutes > 59 || parts.seconds > 59) {\n return null;\n }\n const date = fromParts(parts, zone, Number(ms.padEnd(3, '0')));\n return sameDay(dayKeyOf(date, zone), parts) ? date : null;\n }\n const date = value instanceof Date ? value : new Date(value);\n return isValidDate(date) ? date : null;\n};\n\nexport const withTime = (\n day: DayKey,\n time: Pick<DateTimeParts, 'hours' | 'minutes' | 'seconds'>,\n zone: DatePickerTimeZone,\n): Date =>\n fromParts(\n {\n year: day.year,\n month: day.month,\n day: day.day,\n hours: time.hours,\n minutes: time.minutes,\n seconds: time.seconds,\n },\n zone,\n );\n\nconst UNIT_MS: Record<Exclude<DatePickerPrecision, 'day'>, number> = {\n minute: 60_000,\n second: 1_000,\n};\n\n// Arithmetic, not a rebuild from local fields, which moves the repeated hour when clocks go back.\nexport const truncateTo = (\n date: Date,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): Date => {\n if (precision === 'day') {\n return startOfDay(partsOf(date, zone), zone);\n }\n if (zone === 'local' && !Number.isInteger(date.getTimezoneOffset())) {\n const parts = partsOf(date, zone);\n return fromParts({ ...parts, seconds: precision === 'second' ? parts.seconds : 0 }, zone);\n }\n const unit = UNIT_MS[precision];\n return new Date(Math.floor(date.getTime() / unit) * unit);\n};\n\n/** The last millisecond of the unit `date` falls in, so a range end covers the whole of it. */\nexport const endOfUnit = (\n date: Date,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): Date =>\n precision === 'day'\n ? endOfDay(dayKeyOf(date, zone), zone)\n : new Date(truncateTo(date, zone, precision).getTime() + UNIT_MS[precision] - 1);\n\nexport const ceilTo = (\n date: Date,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): Date => {\n if (precision === 'day') {\n return date;\n }\n const floor = truncateTo(date, zone, precision);\n return floor.getTime() < date.getTime()\n ? new Date(floor.getTime() + UNIT_MS[precision])\n : floor;\n};\n"],"names":["MONTHS_SHORT","WEEKDAYS_SHORT","WEEKDAYS_LONG","partsOf","date","zone","fromParts","year","month","day","hours","minutes","seconds","milliseconds","shift","dayKeyOf","compareDays","a","b","sameDay","dayKeyString","startOfDay","endOfDay","addDays","amount","daysInMonth","addMonths","total","addMonthsToDay","target","weekdayOf","WEEK_START_INDEX","weekdayLabels","weekStart","_","index","weekday","monthWeeks","view","first","lead","cellCount","start","weeks","startOfWeek","monthLabel","pad","value","formatTime","parts","precision","zoneSuffix","formatDate","formatTimeReadout","spokenDayFormat","spokenDay","clampDate","min","max","overlapsBounds","from","to","isValidDate","ZONELESS","toDate","zoneless","ms","withTime","time","UNIT_MS","truncateTo","unit","endOfUnit","ceilTo","floor"],"mappings":"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"}
1
+ {"version":3,"file":"dateMath.js","sources":["../../src/components/dateMath.ts"],"sourcesContent":["export type DatePickerTimeZone = 'local' | 'utc';\n\nexport type DatePickerPrecision = 'day' | 'minute' | 'second';\n\nexport type WeekStart = 'monday' | 'sunday';\n\nexport interface DayKey {\n year: number;\n month: number;\n day: number;\n}\n\nexport interface MonthKey {\n year: number;\n month: number;\n}\n\nexport interface DateTimeParts extends DayKey {\n hours: number;\n minutes: number;\n seconds: number;\n}\n\nexport interface DateRange {\n start: Date;\n end: Date;\n}\n\nconst MONTHS_SHORT = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n] as const;\n\nconst WEEKDAYS_SHORT = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] as const;\nconst WEEKDAYS_LONG = [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n] as const;\n\nexport const partsOf = (date: Date, zone: DatePickerTimeZone): DateTimeParts =>\n zone === 'utc'\n ? {\n year: date.getUTCFullYear(),\n month: date.getUTCMonth(),\n day: date.getUTCDate(),\n hours: date.getUTCHours(),\n minutes: date.getUTCMinutes(),\n seconds: date.getUTCSeconds(),\n }\n : {\n year: date.getFullYear(),\n month: date.getMonth(),\n day: date.getDate(),\n hours: date.getHours(),\n minutes: date.getMinutes(),\n seconds: date.getSeconds(),\n };\n\n// `Date` reads years 0-99 as 19xx; build 400 years on (same calendar) and move back.\nconst YEAR_SHIFT = 400;\n\nexport const fromParts = (\n { year, month, day, hours = 0, minutes = 0, seconds = 0 }: DayKey & Partial<DateTimeParts>,\n zone: DatePickerTimeZone,\n milliseconds = 0,\n): Date => {\n const shift = year >= 0 && year < 100 ? YEAR_SHIFT : 0;\n if (zone === 'utc') {\n const date = new Date(\n Date.UTC(year + shift, month, day, hours, minutes, seconds, milliseconds),\n );\n if (shift) {\n date.setUTCFullYear(date.getUTCFullYear() - shift);\n }\n return date;\n }\n const date = new Date(year + shift, month, day, hours, minutes, seconds, milliseconds);\n if (shift) {\n date.setFullYear(date.getFullYear() - shift);\n }\n return date;\n};\n\nexport const dayKeyOf = (date: Date, zone: DatePickerTimeZone): DayKey => {\n const { year, month, day } = partsOf(date, zone);\n return { year, month, day };\n};\n\nexport const compareDays = (a: DayKey, b: DayKey): number =>\n a.year - b.year || a.month - b.month || a.day - b.day;\n\nexport const sameDay = (a: DayKey | null | undefined, b: DayKey | null | undefined): boolean =>\n !!a && !!b && compareDays(a, b) === 0;\n\nexport const dayKeyString = ({ year, month, day }: DayKey): string =>\n `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n\nexport const startOfDay = ({ year, month, day }: DayKey, zone: DatePickerTimeZone): Date =>\n fromParts({ year, month, day }, zone);\n\nexport const endOfDay = ({ year, month, day }: DayKey, zone: DatePickerTimeZone): Date =>\n fromParts({ year, month, day, hours: 23, minutes: 59, seconds: 59 }, zone, 999);\n\nexport const addDays = (day: DayKey, amount: number): DayKey =>\n dayKeyOf(fromParts({ year: day.year, month: day.month, day: day.day + amount }, 'utc'), 'utc');\n\nexport const daysInMonth = ({ year, month }: MonthKey): number =>\n dayKeyOf(fromParts({ year, month: month + 1, day: 0 }, 'utc'), 'utc').day;\n\nexport const addMonths = ({ year, month }: MonthKey, amount: number): MonthKey => {\n const total = year * 12 + month + amount;\n return { year: Math.floor(total / 12), month: ((total % 12) + 12) % 12 };\n};\n\nexport const addMonthsToDay = (day: DayKey, amount: number): DayKey => {\n const target = addMonths(day, amount);\n return { ...target, day: Math.min(day.day, daysInMonth(target)) };\n};\n\nexport const weekdayOf = (day: DayKey): number => fromParts(day, 'utc').getUTCDay();\n\nconst WEEK_START_INDEX: Record<WeekStart, number> = { sunday: 0, monday: 1 };\n\nexport const weekdayLabels = (weekStart: WeekStart): { short: string; long: string }[] =>\n Array.from({ length: 7 }, (_, index) => {\n const weekday = (index + WEEK_START_INDEX[weekStart]) % 7;\n return { short: WEEKDAYS_SHORT[weekday], long: WEEKDAYS_LONG[weekday] };\n });\n\nexport const monthWeeks = (view: MonthKey, weekStart: WeekStart): DayKey[][] => {\n const first: DayKey = { ...view, day: 1 };\n const lead = (weekdayOf(first) - WEEK_START_INDEX[weekStart] + 7) % 7;\n const start = addDays(first, -lead);\n const weeks: DayKey[][] = [];\n for (let index = 0; index < 42; index++) {\n if (index % 7 === 0) {\n weeks.push([]);\n }\n weeks[weeks.length - 1].push(addDays(start, index));\n }\n return weeks;\n};\n\nexport const startOfWeek = (day: DayKey, weekStart: WeekStart): DayKey =>\n addDays(day, -((weekdayOf(day) - WEEK_START_INDEX[weekStart] + 7) % 7));\n\nexport const monthLabel = ({ year, month }: MonthKey): string => `${MONTHS_SHORT[month]} ${year}`;\n\nconst pad = (value: number): string => String(value).padStart(2, '0');\n\nexport const formatTime = (\n parts: Pick<DateTimeParts, 'hours' | 'minutes' | 'seconds'>,\n precision: DatePickerPrecision,\n): string =>\n precision === 'second'\n ? `${pad(parts.hours)}:${pad(parts.minutes)}:${pad(parts.seconds)}`\n : `${pad(parts.hours)}:${pad(parts.minutes)}`;\n\nconst zoneSuffix = (zone: DatePickerTimeZone): string => (zone === 'utc' ? ' UTC' : '');\n\nexport const formatDate = (\n date: Date,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): string => {\n const parts = partsOf(date, zone);\n const day = `${MONTHS_SHORT[parts.month]} ${parts.day} ${parts.year}`;\n return precision === 'day' ? day : `${day}, ${formatTime(parts, precision)}${zoneSuffix(zone)}`;\n};\n\nexport const formatTimeReadout = (\n date: Date | null,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): string =>\n `${date ? formatTime(partsOf(date, zone), precision) : precision === 'second' ? '--:--:--' : '--:--'}${zoneSuffix(zone)}`;\n\n// Lazy, so importing the module has no side effects.\nlet spokenDayFormat: Intl.DateTimeFormat | undefined;\n\nexport const spokenDay = (day: DayKey): string => {\n spokenDayFormat ??= new Intl.DateTimeFormat('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n timeZone: 'UTC',\n });\n return spokenDayFormat.format(fromParts(day, 'utc'));\n};\n\nexport const clampDate = (date: Date, min?: Date, max?: Date): Date => {\n if (min && date.getTime() < min.getTime()) {\n return new Date(min.getTime());\n }\n if (max && date.getTime() > max.getTime()) {\n return new Date(max.getTime());\n }\n return date;\n};\n\nexport const overlapsBounds = (from: Date, to: Date, min?: Date, max?: Date): boolean =>\n (!min || to.getTime() >= min.getTime()) && (!max || from.getTime() <= max.getTime());\n\nconst isValidDate = (value: unknown): value is Date =>\n value instanceof Date && !Number.isNaN(value.getTime());\n\nconst ZONELESS = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{1,3}))?)?)?$/;\n\nexport const toDate = (\n value: Date | string | number | null | undefined,\n zone: DatePickerTimeZone,\n): Date | null => {\n if (value === null || value === undefined || value === '') {\n return null;\n }\n // Without an offset, a string names a wall-clock time in `zone`, not in the browser's.\n const zoneless = typeof value === 'string' ? ZONELESS.exec(value) : null;\n if (zoneless) {\n const [, year, month, day, hours = '0', minutes = '0', seconds = '0', ms = ''] = zoneless;\n const parts = {\n year: Number(year),\n month: Number(month) - 1,\n day: Number(day),\n hours: Number(hours),\n minutes: Number(minutes),\n seconds: Number(seconds),\n };\n if (parts.hours > 23 || parts.minutes > 59 || parts.seconds > 59) {\n return null;\n }\n const date = fromParts(parts, zone, Number(ms.padEnd(3, '0')));\n return sameDay(dayKeyOf(date, zone), parts) ? date : null;\n }\n const date = value instanceof Date ? value : new Date(value);\n return isValidDate(date) ? date : null;\n};\n\nexport const withTime = (\n day: DayKey,\n time: Pick<DateTimeParts, 'hours' | 'minutes' | 'seconds'>,\n zone: DatePickerTimeZone,\n): Date =>\n fromParts(\n {\n year: day.year,\n month: day.month,\n day: day.day,\n hours: time.hours,\n minutes: time.minutes,\n seconds: time.seconds,\n },\n zone,\n );\n\nconst UNIT_MS: Record<Exclude<DatePickerPrecision, 'day'>, number> = {\n minute: 60_000,\n second: 1_000,\n};\n\n// Arithmetic, not a rebuild from local fields, which moves the repeated hour when clocks go back.\nexport const truncateTo = (\n date: Date,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): Date => {\n if (precision === 'day') {\n return startOfDay(partsOf(date, zone), zone);\n }\n if (zone === 'local' && !Number.isInteger(date.getTimezoneOffset())) {\n const parts = partsOf(date, zone);\n return fromParts({ ...parts, seconds: precision === 'second' ? parts.seconds : 0 }, zone);\n }\n const unit = UNIT_MS[precision];\n return new Date(Math.floor(date.getTime() / unit) * unit);\n};\n\n/** The last millisecond of the unit `date` falls in, so a range end covers the whole of it. */\nexport const endOfUnit = (\n date: Date,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): Date =>\n precision === 'day'\n ? endOfDay(dayKeyOf(date, zone), zone)\n : new Date(truncateTo(date, zone, precision).getTime() + UNIT_MS[precision] - 1);\n\nexport const ceilTo = (\n date: Date,\n zone: DatePickerTimeZone,\n precision: DatePickerPrecision,\n): Date => {\n if (precision === 'day') {\n return date;\n }\n const floor = truncateTo(date, zone, precision);\n return floor.getTime() < date.getTime()\n ? new Date(floor.getTime() + UNIT_MS[precision])\n : floor;\n};\n"],"names":["MONTHS_SHORT","WEEKDAYS_SHORT","WEEKDAYS_LONG","partsOf","date","zone","fromParts","year","month","day","hours","minutes","seconds","milliseconds","shift","dayKeyOf","compareDays","a","b","sameDay","dayKeyString","startOfDay","endOfDay","addDays","amount","daysInMonth","addMonths","total","addMonthsToDay","target","weekdayOf","WEEK_START_INDEX","weekdayLabels","weekStart","_","index","weekday","monthWeeks","view","first","lead","start","weeks","startOfWeek","monthLabel","pad","value","formatTime","parts","precision","zoneSuffix","formatDate","formatTimeReadout","spokenDayFormat","spokenDay","clampDate","min","max","overlapsBounds","from","to","isValidDate","ZONELESS","toDate","zoneless","ms","withTime","time","UNIT_MS","truncateTo","unit","endOfUnit","ceilTo","floor"],"mappings":"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"}
@@ -1,119 +1,123 @@
1
1
  import { useSyncExternalStore as b, useRef as f, useCallback as N, useEffect as E, useLayoutEffect as m } from "react";
2
- import { getDeepActiveElement as k, containsComposed as F } from "./activeElement.js";
3
- import { pushEscapeLayer as K } from "./escapeLayers.js";
4
- import { FOCUS_RING as W } from "./focusRing.js";
5
- import { nextLayerTicket as V, popupLayerHolding as Y } from "./overlayLayers.js";
6
- import { useOwnedByPopover as j } from "./popoverTree.js";
7
- import { OVERLAY_Z_BASE as R, ensureElevatedOverlayStyles as Z } from "./portalOverlay.js";
8
- import { lockBodyScroll as $ } from "./scrollLock.js";
9
- import { leaveTopLayer as U, raiseToTopLayer as q } from "./topLayer.js";
10
- const Ot = `flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-[4px] text-[var(--malachite-text-secondary)] hover:text-[var(--malachite-text-primary)] transition-colors ${W}`, J = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, [tabindex]:not([tabindex="-1"])', Q = (t) => t.assignedSlot ?? t.parentElement ?? (t.parentNode instanceof ShadowRoot ? t.parentNode.host : null), X = (t) => Array.from(t.children).find((o) => o.tagName === "SUMMARY"), tt = () => {
11
- const t = /* @__PURE__ */ new Map(), o = (n) => {
12
- const e = t.get(n);
13
- if (e)
14
- return e;
15
- const { display: a, visibility: r, contentVisibility: s } = getComputedStyle(n), c = Q(n), d = c ? o(c) : null, h = c instanceof HTMLDetailsElement && !c.open && X(c) !== n, l = {
16
- hidden: n.hasAttribute("inert") || a === "none" || h || !!(d && (d.hidden || d.hidesContent)),
2
+ import { getDeepActiveElement as R, containsComposed as B } from "./activeElement.js";
3
+ import { pushEscapeLayer as V } from "./escapeLayers.js";
4
+ import { FOCUS_RING as Y } from "./focusRing.js";
5
+ import { nextLayerTicket as j, popupLayerHolding as Z } from "./overlayLayers.js";
6
+ import { useOwnedByPopover as $ } from "./popoverTree.js";
7
+ import { OVERLAY_Z_BASE as _, ensureElevatedOverlayStyles as q } from "./portalOverlay.js";
8
+ import { lockBodyScroll as J } from "./scrollLock.js";
9
+ import { leaveTopLayer as G, raiseToTopLayer as M } from "./topLayer.js";
10
+ const Tt = `flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-[4px] text-[var(--malachite-text-secondary)] hover:text-[var(--malachite-text-primary)] transition-colors ${Y}`, Q = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, [tabindex]:not([tabindex="-1"])', X = (t) => t.assignedSlot ?? t.parentElement ?? (t.parentNode instanceof ShadowRoot ? t.parentNode.host : null), tt = (t) => Array.from(t.children).find((o) => o.tagName === "SUMMARY"), et = () => {
11
+ const t = /* @__PURE__ */ new Map(), o = (e) => {
12
+ const n = t.get(e);
13
+ if (n)
14
+ return n;
15
+ const { display: a, visibility: r, contentVisibility: s } = getComputedStyle(e), c = X(e), d = c ? o(c) : null, h = c instanceof HTMLDetailsElement && !c.open && tt(c) !== e, l = {
16
+ hidden: e.hasAttribute("inert") || a === "none" || h || !!(d && (d.hidden || d.hidesContent)),
17
17
  invisible: r === "hidden" || r === "collapse",
18
18
  hidesContent: s === "hidden"
19
19
  };
20
- return t.set(n, l), l;
20
+ return t.set(e, l), l;
21
21
  };
22
22
  return o;
23
23
  }, nt = (t, o) => {
24
24
  if (t.tabIndex < 0 || t.matches(":disabled"))
25
25
  return !1;
26
- const { hidden: n, invisible: e } = o(t);
27
- return !n && !e;
28
- }, _ = (t) => t instanceof HTMLInputElement && t.type === "radio" && t.name !== "", et = (t, o) => {
29
- if (!_(t))
26
+ const { hidden: e, invisible: n } = o(t);
27
+ return !e && !n;
28
+ }, v = (t) => t instanceof HTMLInputElement && t.type === "radio" && t.name !== "", ot = (t, o) => {
29
+ if (!v(t))
30
30
  return !1;
31
- const n = o.filter(
32
- (e) => _(e) && e.name === t.name && e.form === t.form
31
+ const e = o.filter(
32
+ (n) => v(n) && n.name === t.name && n.form === t.form
33
33
  );
34
- return (n.find((e) => e.checked) ?? n[0]) !== t;
35
- }, ot = (t, o) => t.map((n, e) => ({ element: n, index: e, tabIndex: o(n) })).sort((n, e) => n.tabIndex !== e.tabIndex ? n.tabIndex === 0 ? 1 : e.tabIndex === 0 ? -1 : n.tabIndex - e.tabIndex : n.index - e.index).map(({ element: n }) => n), x = (t) => t instanceof HTMLSlotElement && t.getRootNode() instanceof ShadowRoot, I = (t, o = []) => {
36
- for (const n of t)
37
- o.push(n), !n.shadowRoot && !x(n) && I(n.children, o);
34
+ return (e.find((n) => n.checked) ?? e[0]) !== t;
35
+ }, rt = (t, o) => t.map((e, n) => ({ element: e, index: n, tabIndex: o(e) })).sort((e, n) => e.tabIndex !== n.tabIndex ? e.tabIndex === 0 ? 1 : n.tabIndex === 0 ? -1 : e.tabIndex - n.tabIndex : e.index - n.index).map(({ element: e }) => e), x = (t) => t instanceof HTMLSlotElement && t.getRootNode() instanceof ShadowRoot, O = (t, o = []) => {
36
+ for (const e of t)
37
+ o.push(e), !e.shadowRoot && !x(e) && O(e.children, o);
38
38
  return o;
39
39
  }, L = (t, o) => {
40
- const n = t.filter(
41
- (r) => r instanceof HTMLElement && r.matches(J) && nt(r, o)
42
- ), e = new Set(
43
- n.filter((r) => !et(r, n))
40
+ const e = t.filter(
41
+ (r) => r instanceof HTMLElement && r.matches(Q) && nt(r, o)
42
+ ), n = new Set(
43
+ e.filter((r) => !ot(r, e))
44
44
  ), a = t.filter(
45
- (r) => e.has(r) || r.shadowRoot || x(r)
45
+ (r) => n.has(r) || r.shadowRoot || x(r)
46
46
  );
47
- return ot(
47
+ return rt(
48
48
  a,
49
- (r) => e.has(r) ? r.tabIndex : 0
49
+ (r) => n.has(r) ? r.tabIndex : 0
50
50
  ).flatMap((r) => {
51
51
  if (x(r))
52
- return L(I(r.assignedElements({ flatten: !0 })), o);
52
+ return L(O(r.assignedElements({ flatten: !0 })), o);
53
53
  const s = r.shadowRoot;
54
54
  if (s && Number.parseInt(r.getAttribute("tabindex") ?? "", 10) < 0)
55
55
  return [];
56
- const c = e.has(r) && !(s != null && s.delegatesFocus) ? [r] : [];
57
- return s ? [...c, ...L(I(s.children), o)] : c;
56
+ const c = n.has(r) && !(s != null && s.delegatesFocus) ? [r] : [];
57
+ return s ? [...c, ...L(O(s.children), o)] : c;
58
58
  });
59
- }, C = (t) => L(I(t.children), tt()), rt = (t, o) => {
60
- const n = (r) => {
59
+ }, C = (t) => L(O(t.children), et()), st = (t, o) => {
60
+ const e = (r) => {
61
61
  const s = [r];
62
62
  for (let c = r.getRootNode(); c instanceof ShadowRoot; c = c.host.getRootNode())
63
63
  s.push(c.host);
64
64
  return s;
65
- }, e = n(t), a = n(o);
66
- for (const r of e) {
65
+ }, n = e(t), a = e(o);
66
+ for (const r of n) {
67
67
  const s = a.find((c) => c.getRootNode() === r.getRootNode());
68
68
  if (s)
69
69
  return r !== s ? r.compareDocumentPosition(s) : r === t ? Node.DOCUMENT_POSITION_FOLLOWING : Node.DOCUMENT_POSITION_PRECEDING;
70
70
  }
71
71
  return Node.DOCUMENT_POSITION_DISCONNECTED;
72
- }, st = (t) => C(t)[0] ?? null, u = [], p = /* @__PURE__ */ new Set(), w = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new Map(), D = /* @__PURE__ */ new Set(), ct = () => {
72
+ }, ct = (t) => C(t)[0] ?? null, u = [], p = /* @__PURE__ */ new Set(), k = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new Set(), at = () => {
73
73
  };
74
74
  let y = [];
75
- const at = () => {
76
- const t = p.size ? u.map((n) => {
77
- var e;
78
- return (e = w.get(n)) == null ? void 0 : e();
79
- }).filter((n) => !!n) : [];
80
- if (t.length === y.length && t.every((n, e) => n === y[e]))
75
+ const D = /* @__PURE__ */ new Set(), it = () => {
76
+ const t = p.size ? u.map((e) => {
77
+ var n;
78
+ return (n = k.get(e)) == null ? void 0 : n();
79
+ }).filter((e) => !!e) : [];
80
+ if (t.length === y.length && t.every((e, n) => e === y[n]))
81
81
  return;
82
82
  const o = new Set(t);
83
- for (const n of y)
84
- o.has(n) || U(n);
85
- for (const n of t)
86
- q(n);
83
+ for (const e of y)
84
+ o.has(e) || G(e);
85
+ for (const e of t)
86
+ M(e);
87
87
  y = t;
88
- }, O = () => {
89
- for (const t of D)
90
- t();
91
- }, B = (t) => (D.add(t), () => {
88
+ for (const e of D)
89
+ M(e);
90
+ }, Nt = (t) => (D.add(t), () => {
92
91
  D.delete(t);
93
- }), M = (t, o, n, e) => {
94
- const a = e[0], r = e[e.length - 1], s = F(n, o);
95
- if (o && s && o !== n && !e.includes(o)) {
92
+ }), I = () => {
93
+ for (const t of g)
94
+ t();
95
+ }, P = (t) => (g.add(t), () => {
96
+ g.delete(t);
97
+ }), A = (t, o, e, n) => {
98
+ const a = n[0], r = n[n.length - 1], s = B(e, o);
99
+ if (o && s && o !== e && !n.includes(o)) {
96
100
  const c = t.shiftKey ? Node.DOCUMENT_POSITION_PRECEDING : Node.DOCUMENT_POSITION_FOLLOWING;
97
- e.some((d) => rt(o, d) & c) || (t.preventDefault(), (t.shiftKey ? r : a).focus());
101
+ n.some((d) => st(o, d) & c) || (t.preventDefault(), (t.shiftKey ? r : a).focus());
98
102
  return;
99
103
  }
100
- t.shiftKey ? (!s || o === a || o === n) && (t.preventDefault(), r.focus()) : (!s || o === r || o === n) && (t.preventDefault(), a.focus());
101
- }, v = (t) => {
104
+ t.shiftKey ? (!s || o === a || o === e) && (t.preventDefault(), r.focus()) : (!s || o === r || o === e) && (t.preventDefault(), a.focus());
105
+ }, F = (t) => {
102
106
  if (t.key !== "Tab" || t.defaultPrevented)
103
107
  return;
104
- let o = null, n = 0;
108
+ let o = null, e = 0;
105
109
  for (let s = u.length - 1; s >= 0 && !o; s -= 1)
106
- o = u[s](), o && (n = g.get(u[s]) ?? 0);
110
+ o = u[s](), o && (e = w.get(u[s]) ?? 0);
107
111
  if (!o)
108
112
  return;
109
- const e = k(), a = e ? Y(e) : null;
110
- if (e && a && a.ticket > n) {
113
+ const n = R(), a = n ? Z(n) : null;
114
+ if (n && a && a.ticket > e) {
111
115
  const s = a.popup.shadowRoot ?? a.popup, c = C(s);
112
116
  if (c.length === 0) {
113
117
  t.preventDefault();
114
118
  return;
115
119
  }
116
- M(t, e, s, c);
120
+ A(t, n, s, c);
117
121
  return;
118
122
  }
119
123
  const r = C(o);
@@ -121,35 +125,35 @@ const at = () => {
121
125
  t.preventDefault(), o.focus();
122
126
  return;
123
127
  }
124
- M(t, e, o, r);
125
- }, it = (t, o) => (u.length === 0 && document.addEventListener("keydown", v), u.push(t), w.set(t, o), g.set(t, V()), O(), () => {
126
- const n = u.lastIndexOf(t);
127
- n !== -1 && u.splice(n, 1), p.delete(t), w.delete(t), g.delete(t);
128
- const e = o();
129
- e && U(e), u.length === 0 && document.removeEventListener("keydown", v), O();
130
- }), Tt = () => b(
131
- B,
128
+ A(t, n, o, r);
129
+ }, ut = (t, o) => (u.length === 0 && document.addEventListener("keydown", F), u.push(t), k.set(t, o), w.set(t, j()), I(), () => {
130
+ const e = u.lastIndexOf(t);
131
+ e !== -1 && u.splice(e, 1), p.delete(t), k.delete(t), w.delete(t);
132
+ const n = o();
133
+ n && G(n), u.length === 0 && document.removeEventListener("keydown", F), I();
134
+ }), Et = () => b(
135
+ P,
132
136
  () => u.length > 0,
133
137
  () => !1
134
- ), A = (t, o) => {
138
+ ), U = (t, o) => {
135
139
  if (o === "content") {
136
- const n = k();
137
- if (F(t, n))
140
+ const e = R();
141
+ if (B(t, e))
138
142
  return;
139
- (st(t) ?? t).focus();
143
+ (ct(t) ?? t).focus();
140
144
  return;
141
145
  }
142
146
  t.focus();
143
- }, Nt = ({
147
+ }, mt = ({
144
148
  open: t,
145
149
  onClose: o,
146
- elevated: n = !1,
147
- hostRef: e,
150
+ elevated: e = !1,
151
+ hostRef: n,
148
152
  initialFocus: a = "panel"
149
153
  }) => {
150
154
  const r = f(null), s = f(() => r.current).current;
151
- j(
152
- N(() => (e == null ? void 0 : e.current) ?? r.current, [e]),
155
+ $(
156
+ N(() => (n == null ? void 0 : n.current) ?? r.current, [n]),
153
157
  t
154
158
  );
155
159
  const c = f(null), d = f(null), h = f(a), l = f(o);
@@ -157,7 +161,7 @@ const at = () => {
157
161
  l.current = o;
158
162
  }, [o]), E(() => {
159
163
  if (t)
160
- return c.current = k(), () => {
164
+ return c.current = R(), () => {
161
165
  const i = c.current;
162
166
  c.current = null, i != null && i.isConnected && i.focus();
163
167
  };
@@ -165,20 +169,20 @@ const at = () => {
165
169
  if (!t)
166
170
  return;
167
171
  d.current = s;
168
- const i = K(() => l.current()), H = $(), z = it(s, () => (e == null ? void 0 : e.current) ?? null);
169
- return r.current && A(r.current, h.current), () => {
170
- d.current = null, z(), i(), H();
172
+ const i = V(() => l.current()), K = J(), W = ut(s, () => (n == null ? void 0 : n.current) ?? null);
173
+ return r.current && U(r.current, h.current), () => {
174
+ d.current = null, W(), i(), K();
171
175
  };
172
- }, [t, e, s]), m(() => {
173
- if (!(!t || !n))
174
- return p.add(s), O(), () => {
175
- p.delete(s), O();
176
+ }, [t, n, s]), m(() => {
177
+ if (!(!t || !e))
178
+ return p.add(s), I(), () => {
179
+ p.delete(s), I();
176
180
  };
177
- }, [t, n, s]);
181
+ }, [t, e, s]);
178
182
  const T = N(
179
- (i) => t ? B(i) : ct,
183
+ (i) => t ? P(i) : at,
180
184
  [t]
181
- ), G = b(
185
+ ), H = b(
182
186
  T,
183
187
  // Gated on `open` so an overlay fading out stops claiming modal. Before it registers
184
188
  // it is the one about to go on top, or aria-modal would drop for a frame on open.
@@ -186,29 +190,30 @@ const at = () => {
186
190
  () => !0
187
191
  ), S = b(
188
192
  T,
189
- () => t && (n || p.size > 0),
193
+ () => t && (e || p.size > 0),
190
194
  () => !1
191
- ), P = b(
195
+ ), z = b(
192
196
  T,
193
197
  () => {
194
198
  const i = d.current;
195
- return R + (t && i ? Math.max(0, u.indexOf(i)) : 0);
199
+ return _ + (t && i ? Math.max(0, u.indexOf(i)) : 0);
196
200
  },
197
- () => R
201
+ () => _
198
202
  );
199
203
  return m(() => {
200
- S && Z();
204
+ S && q();
201
205
  }, [S]), m(() => {
202
- at();
206
+ it();
203
207
  }), { ref: N((i) => {
204
- r.current = i, i && A(i, h.current);
205
- }, []), isTopmost: G, zIndex: S ? void 0 : P, elevated: S };
208
+ r.current = i, i && U(i, h.current);
209
+ }, []), isTopmost: H, zIndex: S ? void 0 : z, elevated: S };
206
210
  };
207
211
  export {
208
- J as FOCUSABLE_SELECTOR,
209
- Ot as OVERLAY_ICON_BUTTON_CLASSES,
210
- st as firstTabStopIn,
211
- Tt as useHasOpenOverlay,
212
- Nt as useOverlayBehaviour
212
+ Q as FOCUSABLE_SELECTOR,
213
+ Tt as OVERLAY_ICON_BUTTON_CLASSES,
214
+ ct as firstTabStopIn,
215
+ Nt as keepAboveOverlayStack,
216
+ Et as useHasOpenOverlay,
217
+ mt as useOverlayBehaviour
213
218
  };
214
219
  //# sourceMappingURL=overlayBehaviour.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"overlayBehaviour.js","sources":["../../src/components/overlayBehaviour.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef, useSyncExternalStore } from 'react';\nimport { containsComposed, getDeepActiveElement } from './activeElement';\nimport { pushEscapeLayer } from './escapeLayers';\nimport { FOCUS_RING } from './focusRing';\nimport { nextLayerTicket, popupLayerHolding } from './overlayLayers';\nimport { useOwnedByPopover } from './popoverTree';\nimport { OVERLAY_Z_BASE, ensureElevatedOverlayStyles } from './portalOverlay';\nimport { lockBodyScroll } from './scrollLock';\nimport { leaveTopLayer, raiseToTopLayer } from './topLayer';\n\n/** Back/close button chrome, shared so the two overlays cannot drift apart. */\nexport const OVERLAY_ICON_BUTTON_CLASSES = `flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-[4px] text-[var(--malachite-text-secondary)] hover:text-[var(--malachite-text-primary)] transition-colors ${FOCUS_RING}`;\n\n// `summary`: a disclosure's first one is a native tab stop and its only keyboard control. A loose\n// one reports `tabIndex === -1`, which `isTabStop` drops.\nexport const FOCUSABLE_SELECTOR =\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, [tabindex]:not([tabindex=\"-1\"])';\n\n// The flat-tree parent: a slotted element renders under its slot, a shadow root under its host.\nconst flatParent = (element: Element): Element | null =>\n element.assignedSlot ??\n element.parentElement ??\n (element.parentNode instanceof ShadowRoot ? element.parentNode.host : null);\n\n// `children`, not `:scope > summary`: inside a shadow root jsdom's selector engine matches\n// nothing for `:scope`, which silently hid the summary along with the rest.\nconst firstSummaryOf = (details: HTMLDetailsElement): Element | undefined =>\n Array.from(details.children).find((child) => child.tagName === 'SUMMARY');\n\ntype RenderState = { hidden: boolean; invisible: boolean; hidesContent: boolean };\n\n// Reads computed style: call at interaction time only, never from a mount path. Under jsdom,\n// `offsetParent`, `getClientRects()` and `checkVisibility()` report every element invisible.\n// One per Tab press, so an ancestor shared by many controls has its style read once.\nconst createRenderStates = (): ((element: Element) => RenderState) => {\n const states = new Map<Element, RenderState>();\n const stateOf = (element: Element): RenderState => {\n const cached = states.get(element);\n if (cached) {\n return cached;\n }\n const { display, visibility, contentVisibility } = getComputedStyle(element);\n const parent = flatParent(element);\n const parentState = parent ? stateOf(parent) : null;\n // A closed `<details>` hides all but its summary in the UA shadow slot, so the hidden\n // descendants keep `tabIndex === 0` and a normal computed display.\n const closedDisclosure =\n parent instanceof HTMLDetailsElement &&\n !parent.open &&\n firstSummaryOf(parent) !== element;\n const state = {\n hidden:\n element.hasAttribute('inert') ||\n display === 'none' ||\n closedDisclosure ||\n Boolean(parentState && (parentState.hidden || parentState.hidesContent)),\n invisible: visibility === 'hidden' || visibility === 'collapse',\n hidesContent: contentVisibility === 'hidden',\n };\n states.set(element, state);\n return state;\n };\n return stateOf;\n};\n\nconst isTabStop = (element: HTMLElement, stateOf: (element: Element) => RenderState): boolean => {\n if (element.tabIndex < 0 || element.matches(':disabled')) {\n return false;\n }\n const { hidden, invisible } = stateOf(element);\n\n return !hidden && !invisible;\n};\n\nconst isGroupedRadio = (element: Element): element is HTMLInputElement =>\n element instanceof HTMLInputElement && element.type === 'radio' && element.name !== '';\n\n// Only a group's checked radio, or its first with none checked, is a tab stop, yet every member\n// reports `tabIndex === 0`.\nconst skipsWithinRadioGroup = (element: HTMLElement, reachable: HTMLElement[]): boolean => {\n if (!isGroupedRadio(element)) {\n return false;\n }\n const group = reachable.filter(\n (candidate): candidate is HTMLInputElement =>\n isGroupedRadio(candidate) &&\n candidate.name === element.name &&\n candidate.form === element.form,\n );\n\n return (group.find((radio) => radio.checked) ?? group[0]) !== element;\n};\n\nconst inTabOrder = (entries: Element[], tabIndexOf: (element: Element) => number): Element[] =>\n entries\n .map((element, index) => ({ element, index, tabIndex: tabIndexOf(element) }))\n .sort((left, right) => {\n if (left.tabIndex !== right.tabIndex) {\n if (left.tabIndex === 0) {\n return 1;\n }\n if (right.tabIndex === 0) {\n return -1;\n }\n\n return left.tabIndex - right.tabIndex;\n }\n\n return left.index - right.index;\n })\n .map(({ element }) => element);\n\n// Only a slot inside a shadow root projects assigned content; elsewhere it renders its children.\nconst isShadowSlot = (element: Element): element is HTMLSlotElement =>\n element instanceof HTMLSlotElement && element.getRootNode() instanceof ShadowRoot;\n\n// One focus navigation scope in tree order. A host's light children render only through its\n// slots, and hosts and slots each own a scope, so the walk descends into neither.\nconst scopeMembers = (elements: Iterable<Element>, into: Element[] = []): Element[] => {\n for (const element of elements) {\n into.push(element);\n if (!element.shadowRoot && !isShadowSlot(element)) {\n scopeMembers(element.children, into);\n }\n }\n return into;\n};\n\n// Ordered per scope, as browsers do: positive tabindex orders within its own scope, and a nested\n// scope takes its owner's place, an owner that is no stop itself ordering as tabindex 0.\nconst stopsInScope = (\n members: Element[],\n stateOf: (element: Element) => RenderState,\n): HTMLElement[] => {\n const reachable = members.filter(\n (element): element is HTMLElement =>\n element instanceof HTMLElement &&\n element.matches(FOCUSABLE_SELECTOR) &&\n isTabStop(element, stateOf),\n );\n const stops = new Set<Element>(\n reachable.filter((element) => !skipsWithinRadioGroup(element, reachable)),\n );\n const entries = members.filter(\n (element) => stops.has(element) || element.shadowRoot || isShadowSlot(element),\n );\n\n return inTabOrder(entries, (element) =>\n stops.has(element) ? (element as HTMLElement).tabIndex : 0,\n ).flatMap((element) => {\n if (isShadowSlot(element)) {\n return stopsInScope(scopeMembers(element.assignedElements({ flatten: true })), stateOf);\n }\n const root = element.shadowRoot;\n // A host given a negative tabindex keeps its whole shadow tree out of the order; an\n // unparsable value counts as absent, as it does for any element.\n if (root && Number.parseInt(element.getAttribute('tabindex') ?? '', 10) < 0) {\n return [];\n }\n const own = stops.has(element) && !root?.delegatesFocus ? [element as HTMLElement] : [];\n\n return root ? [...own, ...stopsInScope(scopeMembers(root.children), stateOf)] : own;\n });\n};\n\nconst tabStopsIn = (root: ParentNode): HTMLElement[] =>\n stopsInScope(scopeMembers(root.children), createRenderStates());\n\n// `compareDocumentPosition` calls nodes in different shadow trees disconnected, so lift both\n// into their deepest shared tree first; a host precedes its own shadow content.\nconst composedPosition = (from: Node, to: Node): number => {\n const ancestry = (node: Node): Node[] => {\n const chain = [node];\n for (\n let root = node.getRootNode();\n root instanceof ShadowRoot;\n root = root.host.getRootNode()\n ) {\n chain.push(root.host);\n }\n return chain;\n };\n const fromChain = ancestry(from);\n const toChain = ancestry(to);\n for (const fromStep of fromChain) {\n const toStep = toChain.find((step) => step.getRootNode() === fromStep.getRootNode());\n if (!toStep) {\n continue;\n }\n if (fromStep !== toStep) {\n return fromStep.compareDocumentPosition(toStep);\n }\n\n return fromStep === from\n ? Node.DOCUMENT_POSITION_FOLLOWING\n : Node.DOCUMENT_POSITION_PRECEDING;\n }\n\n return Node.DOCUMENT_POSITION_DISCONNECTED;\n};\n\n/** Where Tab would land first, for initial focus: the raw selector also matches hidden controls. */\nexport const firstTabStopIn = (root: ParentNode): HTMLElement | null => tabStopsIn(root)[0] ?? null;\n\ntype PanelSource = () => HTMLElement | null;\n\n// LIFO like escapeLayers: with a listener per overlay the first-registered one wins, which\n// sent Tab from a dialog into the panel behind it.\nconst trapLayers: PanelSource[] = [];\n// Elevation belongs to the stack: a Modal left in the base band opens behind the panel that\n// elevated it.\nconst elevatedLayers = new Set<PanelSource>();\n// The shadow host per layer, so promotion can replay in stack order.\nconst hostSources = new Map<PanelSource, () => HTMLElement | null>();\nconst trapTickets = new Map<PanelSource, number>();\nconst stackListeners = new Set<() => void>();\nconst NO_SUBSCRIPTION = () => {\n // Nothing to tear down: a closed overlay never subscribed.\n};\n\n// Top-layer paint order is entry order, so replay the whole stack bottom-up rather than letting\n// each overlay promote itself: those effects run in React tree order, which need not match.\nlet promoted: HTMLElement[] = [];\n\nconst syncTopLayer = (): void => {\n const wanted = elevatedLayers.size\n ? trapLayers\n .map((layer) => hostSources.get(layer)?.())\n .filter((host): host is HTMLElement => Boolean(host))\n : [];\n // Compared, not reapplied: this runs on every commit, because a host can appear a commit\n // after the layer that owns it, and re-entering the top layer unprompted costs a recalc.\n if (\n wanted.length === promoted.length &&\n wanted.every((host, index) => host === promoted[index])\n ) {\n return;\n }\n const stillWanted = new Set(wanted);\n for (const host of promoted) {\n if (!stillWanted.has(host)) {\n leaveTopLayer(host);\n }\n }\n for (const host of wanted) {\n raiseToTopLayer(host);\n }\n promoted = wanted;\n};\n\nconst notifyStackChanged = (): void => {\n for (const listener of stackListeners) {\n listener();\n }\n};\n\nconst subscribeToStack = (listener: () => void): (() => void) => {\n stackListeners.add(listener);\n return () => {\n stackListeners.delete(listener);\n };\n};\n\nconst wrapTab = (\n event: KeyboardEvent,\n active: HTMLElement | null,\n within: Node,\n stops: HTMLElement[],\n): void => {\n const first = stops[0];\n const last = stops[stops.length - 1];\n const inside = containsComposed(within, active);\n // A mouse-only control, such as a search Dropdown's caret, is no edge: Tab resumes from its\n // place in the DOM and would leave the overlay where no real stop follows it.\n if (active && inside && active !== within && !stops.includes(active)) {\n const wanted = event.shiftKey\n ? Node.DOCUMENT_POSITION_PRECEDING\n : Node.DOCUMENT_POSITION_FOLLOWING;\n if (!stops.some((stop) => composedPosition(active, stop) & wanted)) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n }\n\n return;\n }\n if (event.shiftKey) {\n if (!inside || active === first || active === within) {\n event.preventDefault();\n last.focus();\n }\n } else if (!inside || active === last || active === within) {\n event.preventDefault();\n first.focus();\n }\n};\n\nconst handleTabKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Tab' || event.defaultPrevented) {\n return;\n }\n // Walk down rather than bail: React detaches refs before flushing the cleanup that pops\n // the layer, so the topmost can be registered-but-null and Tab would escape entirely.\n let panel: HTMLElement | null = null;\n let trapTicket = 0;\n for (let index = trapLayers.length - 1; index >= 0 && !panel; index -= 1) {\n panel = trapLayers[index]();\n if (panel) {\n trapTicket = trapTickets.get(trapLayers[index]) ?? 0;\n }\n }\n if (!panel) {\n return;\n }\n const active = getDeepActiveElement();\n const layer = active ? popupLayerHolding(active) : null;\n if (active && layer && layer.ticket > trapTicket) {\n const root = layer.popup.shadowRoot ?? layer.popup;\n const popupStops = tabStopsIn(root);\n if (popupStops.length === 0) {\n event.preventDefault();\n return;\n }\n wrapTab(event, active, root, popupStops);\n return;\n }\n const focusables = tabStopsIn(panel);\n if (focusables.length === 0) {\n event.preventDefault();\n panel.focus();\n return;\n }\n wrapTab(event, active, panel, focusables);\n};\n\n// On `document` so it also catches focus that escaped behind the overlay.\nconst pushFocusTrapLayer = (getPanel: PanelSource, getHost: () => HTMLElement | null) => {\n if (trapLayers.length === 0) {\n document.addEventListener('keydown', handleTabKeyDown);\n }\n trapLayers.push(getPanel);\n hostSources.set(getPanel, getHost);\n trapTickets.set(getPanel, nextLayerTicket());\n notifyStackChanged();\n return () => {\n const index = trapLayers.lastIndexOf(getPanel);\n if (index !== -1) {\n trapLayers.splice(index, 1);\n }\n elevatedLayers.delete(getPanel);\n hostSources.delete(getPanel);\n trapTickets.delete(getPanel);\n const host = getHost();\n if (host) {\n leaveTopLayer(host);\n }\n if (trapLayers.length === 0) {\n document.removeEventListener('keydown', handleTabKeyDown);\n }\n notifyStackChanged();\n };\n};\n\n/**\n * Whether a SidePanel, Modal or CommandPalette is open anywhere, for host chrome that has to move out of the way.\n * Overlays portal, so the only other signal is this module's markers, which a host cannot read\n * without coupling to an internal. Dropdowns and tooltips do not count: they trap no focus.\n */\nexport const useHasOpenOverlay = (): boolean =>\n useSyncExternalStore(\n subscribeToStack,\n () => trapLayers.length > 0,\n () => false,\n );\n\nconst takeInitialFocus = (panel: HTMLElement, initialFocus: 'panel' | 'content'): void => {\n if (initialFocus === 'content') {\n const active = getDeepActiveElement();\n if (containsComposed(panel, active)) {\n return;\n }\n (firstTabStopIn(panel) ?? panel).focus();\n return;\n }\n panel.focus();\n};\n\n/**\n * The modal-overlay behaviour shared by SidePanel, Modal and CommandPalette: ESC and the Tab focus trap\n * (topmost overlay only, so these may be stacked), background scroll lock, and focus moved\n * into the overlay on open then restored to the trigger on close.\n *\n * Returns the ref callback the dialog element must take, whether this overlay is the topmost\n * one — only that one may claim `aria-modal`, or a screen reader can still browse the overlay\n * underneath — the z-index its host must carry, which keeps paint order with the focus stack,\n * and whether it is elevated. Presentation otherwise stays with the calling component.\n */\nexport const useOverlayBehaviour = ({\n open,\n onClose,\n elevated = false,\n hostRef,\n initialFocus = 'panel',\n}: {\n open: boolean;\n onClose: () => void;\n elevated?: boolean;\n /** The shadow host, which the stack promotes into the top layer while elevated. */\n hostRef?: { current: HTMLElement | null };\n /** Where focus lands on open: the panel itself, or the content's own first control. */\n initialFocus?: 'panel' | 'content';\n}): {\n ref: (node: HTMLElement | null) => void;\n isTopmost: boolean;\n zIndex: number | undefined;\n elevated: boolean;\n} => {\n const panelRef = useRef<HTMLElement | null>(null);\n // One identity for the life of the instance: elevation registers it in the layout phase,\n // before the effect below pushes it onto the stack.\n const source = useRef<PanelSource>(() => panelRef.current).current;\n useOwnedByPopover(\n useCallback(() => hostRef?.current ?? panelRef.current, [hostRef]),\n open,\n );\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const layerRef = useRef<PanelSource | null>(null);\n const initialFocusRef = useRef(initialFocus);\n\n // Ref so the ESC layer registers once per open, not on every inline-onClose change.\n const onCloseRef = useRef(onClose);\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n // Before the trap effect, so the trigger is recorded before focus moves in — and relies on\n // ShadowRootWrapper portaling a commit late, or this would capture the panel itself.\n useEffect(() => {\n if (!open) {\n return;\n }\n previousFocusRef.current = getDeepActiveElement();\n return () => {\n const previous = previousFocusRef.current;\n previousFocusRef.current = null;\n if (previous?.isConnected) {\n previous.focus();\n }\n };\n }, [open]);\n\n useEffect(() => {\n if (!open) {\n return;\n }\n layerRef.current = source;\n const popEscapeLayer = pushEscapeLayer(() => onCloseRef.current());\n const releaseScrollLock = lockBodyScroll();\n const popFocusTrapLayer = pushFocusTrapLayer(source, () => hostRef?.current ?? null);\n // Reopening inside the exit transition reuses the same node, so the ref callback\n // never fires again and nothing would take focus.\n if (panelRef.current) {\n takeInitialFocus(panelRef.current, initialFocusRef.current);\n }\n return () => {\n layerRef.current = null;\n popFocusTrapLayer();\n popEscapeLayer();\n releaseScrollLock();\n };\n }, [open, hostRef, source]);\n\n // Its own effect: re-pushing the trap layer to change elevation would move this overlay to\n // the top of the stack, handing it the Escape and Tab that belong to a dialog above it.\n // Layout, and declared above the sync below, so that sync sees it in the same commit.\n useLayoutEffect(() => {\n if (!open || !elevated) {\n return;\n }\n elevatedLayers.add(source);\n notifyStackChanged();\n return () => {\n elevatedLayers.delete(source);\n notifyStackChanged();\n };\n }, [open, elevated, source]);\n\n // Only an open overlay subscribes: a mounted-but-idle one must carry no at-rest cost,\n // and its snapshot is a constant `false` regardless of what the stack does.\n const subscribe = useCallback(\n (onStackChange: () => void) => (open ? subscribeToStack(onStackChange) : NO_SUBSCRIPTION),\n [open],\n );\n\n const isTopmost = useSyncExternalStore(\n subscribe,\n // Gated on `open` so an overlay fading out stops claiming modal. Before it registers\n // it is the one about to go on top, or aria-modal would drop for a frame on open.\n () =>\n open &&\n (layerRef.current === null || trapLayers[trapLayers.length - 1] === layerRef.current),\n () => true,\n );\n\n // Its own request counts before the stack has it: the layer is not pushed until effects run.\n const stackElevated = useSyncExternalStore(\n subscribe,\n () => open && (elevated || elevatedLayers.size > 0),\n () => false,\n );\n\n // Overlay hosts share one z-index band, so paint order would otherwise fall out of body\n // order: an overlay reopened over a newer one takes the keyboard while painting under it.\n const zIndex = useSyncExternalStore(\n subscribe,\n () => {\n const layer = layerRef.current;\n return OVERLAY_Z_BASE + (open && layer ? Math.max(0, trapLayers.indexOf(layer)) : 0);\n },\n () => OVERLAY_Z_BASE,\n );\n\n // Layout, not passive: the rule has to exist before the first paint the attribute applies to.\n useLayoutEffect(() => {\n if (stackElevated) {\n ensureElevatedOverlayStyles();\n }\n }, [stackElevated]);\n\n // No deps: the host mounts a commit after the layer that owns it, so there is no stack\n // change left to key this on. `syncTopLayer` compares before it touches anything.\n useLayoutEffect(() => {\n syncTopLayer();\n });\n\n const ref = useCallback((node: HTMLElement | null) => {\n panelRef.current = node;\n // The panel mounts fresh on every open, so first attach = time to take focus.\n if (node) {\n takeInitialFocus(node, initialFocusRef.current);\n }\n }, []);\n\n return { ref, isTopmost, zIndex: stackElevated ? undefined : zIndex, elevated: stackElevated };\n};\n\nexport default useOverlayBehaviour;\n"],"names":["OVERLAY_ICON_BUTTON_CLASSES","FOCUS_RING","FOCUSABLE_SELECTOR","flatParent","element","firstSummaryOf","details","child","createRenderStates","states","stateOf","cached","display","visibility","contentVisibility","parent","parentState","closedDisclosure","state","isTabStop","hidden","invisible","isGroupedRadio","skipsWithinRadioGroup","reachable","group","candidate","radio","inTabOrder","entries","tabIndexOf","index","left","right","isShadowSlot","scopeMembers","elements","into","stopsInScope","members","stops","root","own","tabStopsIn","composedPosition","from","to","ancestry","node","chain","fromChain","toChain","fromStep","toStep","step","firstTabStopIn","trapLayers","elevatedLayers","hostSources","trapTickets","stackListeners","NO_SUBSCRIPTION","promoted","syncTopLayer","wanted","layer","_a","host","stillWanted","leaveTopLayer","raiseToTopLayer","notifyStackChanged","listener","subscribeToStack","wrapTab","event","active","within","first","last","inside","containsComposed","stop","handleTabKeyDown","panel","trapTicket","getDeepActiveElement","popupLayerHolding","popupStops","focusables","pushFocusTrapLayer","getPanel","getHost","nextLayerTicket","useHasOpenOverlay","useSyncExternalStore","takeInitialFocus","initialFocus","useOverlayBehaviour","open","onClose","elevated","hostRef","panelRef","useRef","source","useOwnedByPopover","useCallback","previousFocusRef","layerRef","initialFocusRef","onCloseRef","useEffect","previous","popEscapeLayer","pushEscapeLayer","releaseScrollLock","lockBodyScroll","popFocusTrapLayer","useLayoutEffect","subscribe","onStackChange","isTopmost","stackElevated","zIndex","OVERLAY_Z_BASE","ensureElevatedOverlayStyles"],"mappings":"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"}
1
+ {"version":3,"file":"overlayBehaviour.js","sources":["../../src/components/overlayBehaviour.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef, useSyncExternalStore } from 'react';\nimport { containsComposed, getDeepActiveElement } from './activeElement';\nimport { pushEscapeLayer } from './escapeLayers';\nimport { FOCUS_RING } from './focusRing';\nimport { nextLayerTicket, popupLayerHolding } from './overlayLayers';\nimport { useOwnedByPopover } from './popoverTree';\nimport { OVERLAY_Z_BASE, ensureElevatedOverlayStyles } from './portalOverlay';\nimport { lockBodyScroll } from './scrollLock';\nimport { leaveTopLayer, raiseToTopLayer } from './topLayer';\n\n/** Back/close button chrome, shared so the two overlays cannot drift apart. */\nexport const OVERLAY_ICON_BUTTON_CLASSES = `flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-[4px] text-[var(--malachite-text-secondary)] hover:text-[var(--malachite-text-primary)] transition-colors ${FOCUS_RING}`;\n\n// `summary`: a disclosure's first one is a native tab stop and its only keyboard control. A loose\n// one reports `tabIndex === -1`, which `isTabStop` drops.\nexport const FOCUSABLE_SELECTOR =\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, [tabindex]:not([tabindex=\"-1\"])';\n\n// The flat-tree parent: a slotted element renders under its slot, a shadow root under its host.\nconst flatParent = (element: Element): Element | null =>\n element.assignedSlot ??\n element.parentElement ??\n (element.parentNode instanceof ShadowRoot ? element.parentNode.host : null);\n\n// `children`, not `:scope > summary`: inside a shadow root jsdom's selector engine matches\n// nothing for `:scope`, which silently hid the summary along with the rest.\nconst firstSummaryOf = (details: HTMLDetailsElement): Element | undefined =>\n Array.from(details.children).find((child) => child.tagName === 'SUMMARY');\n\ntype RenderState = { hidden: boolean; invisible: boolean; hidesContent: boolean };\n\n// Reads computed style: call at interaction time only, never from a mount path. Under jsdom,\n// `offsetParent`, `getClientRects()` and `checkVisibility()` report every element invisible.\n// One per Tab press, so an ancestor shared by many controls has its style read once.\nconst createRenderStates = (): ((element: Element) => RenderState) => {\n const states = new Map<Element, RenderState>();\n const stateOf = (element: Element): RenderState => {\n const cached = states.get(element);\n if (cached) {\n return cached;\n }\n const { display, visibility, contentVisibility } = getComputedStyle(element);\n const parent = flatParent(element);\n const parentState = parent ? stateOf(parent) : null;\n // A closed `<details>` hides all but its summary in the UA shadow slot, so the hidden\n // descendants keep `tabIndex === 0` and a normal computed display.\n const closedDisclosure =\n parent instanceof HTMLDetailsElement &&\n !parent.open &&\n firstSummaryOf(parent) !== element;\n const state = {\n hidden:\n element.hasAttribute('inert') ||\n display === 'none' ||\n closedDisclosure ||\n Boolean(parentState && (parentState.hidden || parentState.hidesContent)),\n invisible: visibility === 'hidden' || visibility === 'collapse',\n hidesContent: contentVisibility === 'hidden',\n };\n states.set(element, state);\n return state;\n };\n return stateOf;\n};\n\nconst isTabStop = (element: HTMLElement, stateOf: (element: Element) => RenderState): boolean => {\n if (element.tabIndex < 0 || element.matches(':disabled')) {\n return false;\n }\n const { hidden, invisible } = stateOf(element);\n\n return !hidden && !invisible;\n};\n\nconst isGroupedRadio = (element: Element): element is HTMLInputElement =>\n element instanceof HTMLInputElement && element.type === 'radio' && element.name !== '';\n\n// Only a group's checked radio, or its first with none checked, is a tab stop, yet every member\n// reports `tabIndex === 0`.\nconst skipsWithinRadioGroup = (element: HTMLElement, reachable: HTMLElement[]): boolean => {\n if (!isGroupedRadio(element)) {\n return false;\n }\n const group = reachable.filter(\n (candidate): candidate is HTMLInputElement =>\n isGroupedRadio(candidate) &&\n candidate.name === element.name &&\n candidate.form === element.form,\n );\n\n return (group.find((radio) => radio.checked) ?? group[0]) !== element;\n};\n\nconst inTabOrder = (entries: Element[], tabIndexOf: (element: Element) => number): Element[] =>\n entries\n .map((element, index) => ({ element, index, tabIndex: tabIndexOf(element) }))\n .sort((left, right) => {\n if (left.tabIndex !== right.tabIndex) {\n if (left.tabIndex === 0) {\n return 1;\n }\n if (right.tabIndex === 0) {\n return -1;\n }\n\n return left.tabIndex - right.tabIndex;\n }\n\n return left.index - right.index;\n })\n .map(({ element }) => element);\n\n// Only a slot inside a shadow root projects assigned content; elsewhere it renders its children.\nconst isShadowSlot = (element: Element): element is HTMLSlotElement =>\n element instanceof HTMLSlotElement && element.getRootNode() instanceof ShadowRoot;\n\n// One focus navigation scope in tree order. A host's light children render only through its\n// slots, and hosts and slots each own a scope, so the walk descends into neither.\nconst scopeMembers = (elements: Iterable<Element>, into: Element[] = []): Element[] => {\n for (const element of elements) {\n into.push(element);\n if (!element.shadowRoot && !isShadowSlot(element)) {\n scopeMembers(element.children, into);\n }\n }\n return into;\n};\n\n// Ordered per scope, as browsers do: positive tabindex orders within its own scope, and a nested\n// scope takes its owner's place, an owner that is no stop itself ordering as tabindex 0.\nconst stopsInScope = (\n members: Element[],\n stateOf: (element: Element) => RenderState,\n): HTMLElement[] => {\n const reachable = members.filter(\n (element): element is HTMLElement =>\n element instanceof HTMLElement &&\n element.matches(FOCUSABLE_SELECTOR) &&\n isTabStop(element, stateOf),\n );\n const stops = new Set<Element>(\n reachable.filter((element) => !skipsWithinRadioGroup(element, reachable)),\n );\n const entries = members.filter(\n (element) => stops.has(element) || element.shadowRoot || isShadowSlot(element),\n );\n\n return inTabOrder(entries, (element) =>\n stops.has(element) ? (element as HTMLElement).tabIndex : 0,\n ).flatMap((element) => {\n if (isShadowSlot(element)) {\n return stopsInScope(scopeMembers(element.assignedElements({ flatten: true })), stateOf);\n }\n const root = element.shadowRoot;\n // A host given a negative tabindex keeps its whole shadow tree out of the order; an\n // unparsable value counts as absent, as it does for any element.\n if (root && Number.parseInt(element.getAttribute('tabindex') ?? '', 10) < 0) {\n return [];\n }\n const own = stops.has(element) && !root?.delegatesFocus ? [element as HTMLElement] : [];\n\n return root ? [...own, ...stopsInScope(scopeMembers(root.children), stateOf)] : own;\n });\n};\n\nconst tabStopsIn = (root: ParentNode): HTMLElement[] =>\n stopsInScope(scopeMembers(root.children), createRenderStates());\n\n// `compareDocumentPosition` calls nodes in different shadow trees disconnected, so lift both\n// into their deepest shared tree first; a host precedes its own shadow content.\nconst composedPosition = (from: Node, to: Node): number => {\n const ancestry = (node: Node): Node[] => {\n const chain = [node];\n for (\n let root = node.getRootNode();\n root instanceof ShadowRoot;\n root = root.host.getRootNode()\n ) {\n chain.push(root.host);\n }\n return chain;\n };\n const fromChain = ancestry(from);\n const toChain = ancestry(to);\n for (const fromStep of fromChain) {\n const toStep = toChain.find((step) => step.getRootNode() === fromStep.getRootNode());\n if (!toStep) {\n continue;\n }\n if (fromStep !== toStep) {\n return fromStep.compareDocumentPosition(toStep);\n }\n\n return fromStep === from\n ? Node.DOCUMENT_POSITION_FOLLOWING\n : Node.DOCUMENT_POSITION_PRECEDING;\n }\n\n return Node.DOCUMENT_POSITION_DISCONNECTED;\n};\n\n/** Where Tab would land first, for initial focus: the raw selector also matches hidden controls. */\nexport const firstTabStopIn = (root: ParentNode): HTMLElement | null => tabStopsIn(root)[0] ?? null;\n\ntype PanelSource = () => HTMLElement | null;\n\n// LIFO like escapeLayers: with a listener per overlay the first-registered one wins, which\n// sent Tab from a dialog into the panel behind it.\nconst trapLayers: PanelSource[] = [];\n// Elevation belongs to the stack: a Modal left in the base band opens behind the panel that\n// elevated it.\nconst elevatedLayers = new Set<PanelSource>();\n// The shadow host per layer, so promotion can replay in stack order.\nconst hostSources = new Map<PanelSource, () => HTMLElement | null>();\nconst trapTickets = new Map<PanelSource, number>();\nconst stackListeners = new Set<() => void>();\nconst NO_SUBSCRIPTION = () => {\n // Nothing to tear down: a closed overlay never subscribed.\n};\n\n// Top-layer paint order is entry order, so replay the whole stack bottom-up rather than letting\n// each overlay promote itself: those effects run in React tree order, which need not match.\nlet promoted: HTMLElement[] = [];\nconst aboveStack = new Set<HTMLElement>();\n\nconst syncTopLayer = (): void => {\n const wanted = elevatedLayers.size\n ? trapLayers\n .map((layer) => hostSources.get(layer)?.())\n .filter((host): host is HTMLElement => Boolean(host))\n : [];\n // Compared, not reapplied: this runs on every commit, because a host can appear a commit\n // after the layer that owns it, and re-entering the top layer unprompted costs a recalc.\n if (\n wanted.length === promoted.length &&\n wanted.every((host, index) => host === promoted[index])\n ) {\n return;\n }\n const stillWanted = new Set(wanted);\n for (const host of promoted) {\n if (!stillWanted.has(host)) {\n leaveTopLayer(host);\n }\n }\n for (const host of wanted) {\n raiseToTopLayer(host);\n }\n promoted = wanted;\n for (const host of aboveStack) {\n raiseToTopLayer(host);\n }\n};\n\n/** Keeps a promoted host above the elevated stack each time the stack is replayed. */\nexport const keepAboveOverlayStack = (host: HTMLElement): (() => void) => {\n aboveStack.add(host);\n return () => {\n aboveStack.delete(host);\n };\n};\n\nconst notifyStackChanged = (): void => {\n for (const listener of stackListeners) {\n listener();\n }\n};\n\nconst subscribeToStack = (listener: () => void): (() => void) => {\n stackListeners.add(listener);\n return () => {\n stackListeners.delete(listener);\n };\n};\n\nconst wrapTab = (\n event: KeyboardEvent,\n active: HTMLElement | null,\n within: Node,\n stops: HTMLElement[],\n): void => {\n const first = stops[0];\n const last = stops[stops.length - 1];\n const inside = containsComposed(within, active);\n // A mouse-only control, such as a search Dropdown's caret, is no edge: Tab resumes from its\n // place in the DOM and would leave the overlay where no real stop follows it.\n if (active && inside && active !== within && !stops.includes(active)) {\n const wanted = event.shiftKey\n ? Node.DOCUMENT_POSITION_PRECEDING\n : Node.DOCUMENT_POSITION_FOLLOWING;\n if (!stops.some((stop) => composedPosition(active, stop) & wanted)) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n }\n\n return;\n }\n if (event.shiftKey) {\n if (!inside || active === first || active === within) {\n event.preventDefault();\n last.focus();\n }\n } else if (!inside || active === last || active === within) {\n event.preventDefault();\n first.focus();\n }\n};\n\nconst handleTabKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Tab' || event.defaultPrevented) {\n return;\n }\n // Walk down rather than bail: React detaches refs before flushing the cleanup that pops\n // the layer, so the topmost can be registered-but-null and Tab would escape entirely.\n let panel: HTMLElement | null = null;\n let trapTicket = 0;\n for (let index = trapLayers.length - 1; index >= 0 && !panel; index -= 1) {\n panel = trapLayers[index]();\n if (panel) {\n trapTicket = trapTickets.get(trapLayers[index]) ?? 0;\n }\n }\n if (!panel) {\n return;\n }\n const active = getDeepActiveElement();\n const layer = active ? popupLayerHolding(active) : null;\n if (active && layer && layer.ticket > trapTicket) {\n const root = layer.popup.shadowRoot ?? layer.popup;\n const popupStops = tabStopsIn(root);\n if (popupStops.length === 0) {\n event.preventDefault();\n return;\n }\n wrapTab(event, active, root, popupStops);\n return;\n }\n const focusables = tabStopsIn(panel);\n if (focusables.length === 0) {\n event.preventDefault();\n panel.focus();\n return;\n }\n wrapTab(event, active, panel, focusables);\n};\n\n// On `document` so it also catches focus that escaped behind the overlay.\nconst pushFocusTrapLayer = (getPanel: PanelSource, getHost: () => HTMLElement | null) => {\n if (trapLayers.length === 0) {\n document.addEventListener('keydown', handleTabKeyDown);\n }\n trapLayers.push(getPanel);\n hostSources.set(getPanel, getHost);\n trapTickets.set(getPanel, nextLayerTicket());\n notifyStackChanged();\n return () => {\n const index = trapLayers.lastIndexOf(getPanel);\n if (index !== -1) {\n trapLayers.splice(index, 1);\n }\n elevatedLayers.delete(getPanel);\n hostSources.delete(getPanel);\n trapTickets.delete(getPanel);\n const host = getHost();\n if (host) {\n leaveTopLayer(host);\n }\n if (trapLayers.length === 0) {\n document.removeEventListener('keydown', handleTabKeyDown);\n }\n notifyStackChanged();\n };\n};\n\n/**\n * Whether a SidePanel, Modal or CommandPalette is open anywhere, for host chrome that has to move out of the way.\n * Overlays portal, so the only other signal is this module's markers, which a host cannot read\n * without coupling to an internal. Dropdowns and tooltips do not count: they trap no focus.\n */\nexport const useHasOpenOverlay = (): boolean =>\n useSyncExternalStore(\n subscribeToStack,\n () => trapLayers.length > 0,\n () => false,\n );\n\nconst takeInitialFocus = (panel: HTMLElement, initialFocus: 'panel' | 'content'): void => {\n if (initialFocus === 'content') {\n const active = getDeepActiveElement();\n if (containsComposed(panel, active)) {\n return;\n }\n (firstTabStopIn(panel) ?? panel).focus();\n return;\n }\n panel.focus();\n};\n\n/**\n * The modal-overlay behaviour shared by SidePanel, Modal and CommandPalette: ESC and the Tab focus trap\n * (topmost overlay only, so these may be stacked), background scroll lock, and focus moved\n * into the overlay on open then restored to the trigger on close.\n *\n * Returns the ref callback the dialog element must take, whether this overlay is the topmost\n * one — only that one may claim `aria-modal`, or a screen reader can still browse the overlay\n * underneath — the z-index its host must carry, which keeps paint order with the focus stack,\n * and whether it is elevated. Presentation otherwise stays with the calling component.\n */\nexport const useOverlayBehaviour = ({\n open,\n onClose,\n elevated = false,\n hostRef,\n initialFocus = 'panel',\n}: {\n open: boolean;\n onClose: () => void;\n elevated?: boolean;\n /** The shadow host, which the stack promotes into the top layer while elevated. */\n hostRef?: { current: HTMLElement | null };\n /** Where focus lands on open: the panel itself, or the content's own first control. */\n initialFocus?: 'panel' | 'content';\n}): {\n ref: (node: HTMLElement | null) => void;\n isTopmost: boolean;\n zIndex: number | undefined;\n elevated: boolean;\n} => {\n const panelRef = useRef<HTMLElement | null>(null);\n // One identity for the life of the instance: elevation registers it in the layout phase,\n // before the effect below pushes it onto the stack.\n const source = useRef<PanelSource>(() => panelRef.current).current;\n useOwnedByPopover(\n useCallback(() => hostRef?.current ?? panelRef.current, [hostRef]),\n open,\n );\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const layerRef = useRef<PanelSource | null>(null);\n const initialFocusRef = useRef(initialFocus);\n\n // Ref so the ESC layer registers once per open, not on every inline-onClose change.\n const onCloseRef = useRef(onClose);\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n // Before the trap effect, so the trigger is recorded before focus moves in — and relies on\n // ShadowRootWrapper portaling a commit late, or this would capture the panel itself.\n useEffect(() => {\n if (!open) {\n return;\n }\n previousFocusRef.current = getDeepActiveElement();\n return () => {\n const previous = previousFocusRef.current;\n previousFocusRef.current = null;\n if (previous?.isConnected) {\n previous.focus();\n }\n };\n }, [open]);\n\n useEffect(() => {\n if (!open) {\n return;\n }\n layerRef.current = source;\n const popEscapeLayer = pushEscapeLayer(() => onCloseRef.current());\n const releaseScrollLock = lockBodyScroll();\n const popFocusTrapLayer = pushFocusTrapLayer(source, () => hostRef?.current ?? null);\n // Reopening inside the exit transition reuses the same node, so the ref callback\n // never fires again and nothing would take focus.\n if (panelRef.current) {\n takeInitialFocus(panelRef.current, initialFocusRef.current);\n }\n return () => {\n layerRef.current = null;\n popFocusTrapLayer();\n popEscapeLayer();\n releaseScrollLock();\n };\n }, [open, hostRef, source]);\n\n // Its own effect: re-pushing the trap layer to change elevation would move this overlay to\n // the top of the stack, handing it the Escape and Tab that belong to a dialog above it.\n // Layout, and declared above the sync below, so that sync sees it in the same commit.\n useLayoutEffect(() => {\n if (!open || !elevated) {\n return;\n }\n elevatedLayers.add(source);\n notifyStackChanged();\n return () => {\n elevatedLayers.delete(source);\n notifyStackChanged();\n };\n }, [open, elevated, source]);\n\n // Only an open overlay subscribes: a mounted-but-idle one must carry no at-rest cost,\n // and its snapshot is a constant `false` regardless of what the stack does.\n const subscribe = useCallback(\n (onStackChange: () => void) => (open ? subscribeToStack(onStackChange) : NO_SUBSCRIPTION),\n [open],\n );\n\n const isTopmost = useSyncExternalStore(\n subscribe,\n // Gated on `open` so an overlay fading out stops claiming modal. Before it registers\n // it is the one about to go on top, or aria-modal would drop for a frame on open.\n () =>\n open &&\n (layerRef.current === null || trapLayers[trapLayers.length - 1] === layerRef.current),\n () => true,\n );\n\n // Its own request counts before the stack has it: the layer is not pushed until effects run.\n const stackElevated = useSyncExternalStore(\n subscribe,\n () => open && (elevated || elevatedLayers.size > 0),\n () => false,\n );\n\n // Overlay hosts share one z-index band, so paint order would otherwise fall out of body\n // order: an overlay reopened over a newer one takes the keyboard while painting under it.\n const zIndex = useSyncExternalStore(\n subscribe,\n () => {\n const layer = layerRef.current;\n return OVERLAY_Z_BASE + (open && layer ? Math.max(0, trapLayers.indexOf(layer)) : 0);\n },\n () => OVERLAY_Z_BASE,\n );\n\n // Layout, not passive: the rule has to exist before the first paint the attribute applies to.\n useLayoutEffect(() => {\n if (stackElevated) {\n ensureElevatedOverlayStyles();\n }\n }, [stackElevated]);\n\n // No deps: the host mounts a commit after the layer that owns it, so there is no stack\n // change left to key this on. `syncTopLayer` compares before it touches anything.\n useLayoutEffect(() => {\n syncTopLayer();\n });\n\n const ref = useCallback((node: HTMLElement | null) => {\n panelRef.current = node;\n // The panel mounts fresh on every open, so first attach = time to take focus.\n if (node) {\n takeInitialFocus(node, initialFocusRef.current);\n }\n }, []);\n\n return { ref, isTopmost, zIndex: stackElevated ? undefined : zIndex, elevated: stackElevated };\n};\n\nexport default useOverlayBehaviour;\n"],"names":["OVERLAY_ICON_BUTTON_CLASSES","FOCUS_RING","FOCUSABLE_SELECTOR","flatParent","element","firstSummaryOf","details","child","createRenderStates","states","stateOf","cached","display","visibility","contentVisibility","parent","parentState","closedDisclosure","state","isTabStop","hidden","invisible","isGroupedRadio","skipsWithinRadioGroup","reachable","group","candidate","radio","inTabOrder","entries","tabIndexOf","index","left","right","isShadowSlot","scopeMembers","elements","into","stopsInScope","members","stops","root","own","tabStopsIn","composedPosition","from","to","ancestry","node","chain","fromChain","toChain","fromStep","toStep","step","firstTabStopIn","trapLayers","elevatedLayers","hostSources","trapTickets","stackListeners","NO_SUBSCRIPTION","promoted","aboveStack","syncTopLayer","wanted","layer","_a","host","stillWanted","leaveTopLayer","raiseToTopLayer","keepAboveOverlayStack","notifyStackChanged","listener","subscribeToStack","wrapTab","event","active","within","first","last","inside","containsComposed","stop","handleTabKeyDown","panel","trapTicket","getDeepActiveElement","popupLayerHolding","popupStops","focusables","pushFocusTrapLayer","getPanel","getHost","nextLayerTicket","useHasOpenOverlay","useSyncExternalStore","takeInitialFocus","initialFocus","useOverlayBehaviour","open","onClose","elevated","hostRef","panelRef","useRef","source","useOwnedByPopover","useCallback","previousFocusRef","layerRef","initialFocusRef","onCloseRef","useEffect","previous","popEscapeLayer","pushEscapeLayer","releaseScrollLock","lockBodyScroll","popFocusTrapLayer","useLayoutEffect","subscribe","onStackChange","isTopmost","stackElevated","zIndex","OVERLAY_Z_BASE","ensureElevatedOverlayStyles"],"mappings":"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"}