@allxsmith/bestax-bulma 5.48.1 → 5.49.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/dist/bestax.css +1 -1
- package/dist/bestax.css.map +1 -1
- package/dist/esm/form/_pickerInternals/segmentMap.js +7 -7
- package/dist/esm/form/_pickerInternals/segmentMap.js.map +1 -1
- package/dist/esm/helpers/splitterLayout.js +166 -0
- package/dist/esm/helpers/splitterLayout.js.map +1 -0
- package/dist/esm/layout/Splitter.js +374 -0
- package/dist/esm/layout/Splitter.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +533 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/helpers/splitterLayout.d.ts +62 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/layout/Splitter.d.ts +125 -0
- package/dist/types-cjs/helpers/splitterLayout.d.ts +62 -0
- package/dist/types-cjs/index.d.ts +1 -0
- package/dist/types-cjs/layout/Splitter.d.ts +125 -0
- package/dist/versions/bestax-no-dark-mode.css +1 -1
- package/dist/versions/bestax-no-dark-mode.css.map +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
- package/dist/versions/bestax-no-helpers.css +1 -1
- package/dist/versions/bestax-no-helpers.css.map +1 -1
- package/dist/versions/bestax-prefixed.css +1 -1
- package/dist/versions/bestax-prefixed.css.map +1 -1
- package/package.json +2 -2
- package/src/scss/CLAUDE.md +1 -1
- package/src/scss/bestax.scss +1 -0
- package/src/scss/extras.scss +3 -0
- package/src/scss/layout/_index.scss +5 -0
- package/src/scss/layout/_splitter.scss +184 -0
- package/src/scss/versions/bestax-no-dark-mode.scss +1 -0
- package/src/scss/versions/bestax-no-helpers-prefixed.scss +1 -0
- package/src/scss/versions/bestax-no-helpers.scss +1 -0
- package/src/scss/versions/bestax-prefixed.scss +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segmentMap.js","sources":["../../../../src/form/_pickerInternals/segmentMap.ts"],"sourcesContent":["/**\n * Segment-map utility for manual keyboard entry on a date / time picker input.\n * Given a token-format string like `'YYYY-MM-DD'`, `'HH:mm:ss'`, `'hh:mm A'`,\n * or a combined `'YYYY-MM-DD HH:mm'`, we compute the character ranges of each\n * editable segment in the formatted output, plus arithmetic helpers\n * (increment / digit-set) for each kind.\n *\n * Variable-width tokens (`Y`, `YYY`, `M`, `D`, `H`, `h`, `m`, `s`) cause the\n * renderer to emit output of unpredictable width depending on value, which\n * would shift segment boundaries between renders and break the selection.\n * `buildSegmentMap` returns `null` for any format containing those, signalling\n * the caller to fall back to free-form text entry.\n */\n\nimport { addYears, makeDate } from './dateUtils';\n\nexport type SegmentKind =\n | 'year'\n | 'month'\n | 'day'\n | 'hours'\n | 'minutes'\n | 'seconds'\n | 'ampm'\n | 'literal';\n\nexport interface Segment {\n kind: SegmentKind;\n /** Source token (e.g., `'HH'`) for editable segments; literal text for `'literal'`. */\n token: string;\n /** Inclusive char index into the formatted-string output. */\n start: number;\n /** Exclusive char index. */\n end: number;\n /** Populated only when `kind === 'hours'`. */\n hourFormat?: '12' | '24';\n}\n\nexport interface SegmentMap {\n segments: Segment[];\n /** Indices of non-literal segments, left to right. */\n editable: number[];\n}\n\n// Match longest tokens first so `HH` doesn't collapse to two `H`s and `YYYY`\n// doesn't collapse to `YY` + `YY`. The single-char and odd-width variants\n// (`Y`, `YYY`, `M`, `D`, `H`, `h`, `m`, `s`) are matched only so they can be\n// explicitly rejected below — otherwise a format like `'YYY-MM'` would\n// silently mis-tokenize as `YY` + a stray `Y`.\nconst TOKEN_REGEX = /YYYY|YYY|YY|Y|MM|M|DD|D|HH|hh|mm|ss|H|h|m|s|A|a/g;\n\n// Fixed-width tokens render the same number of chars on every value. All are 2\n// wide except the 4-digit year.\nconst tokenWidth = (token: string): number => (token === 'YYYY' ? 4 : 2);\n\nconst KIND_BY_TOKEN: Record<string, SegmentKind> = {\n YYYY: 'year',\n YY: 'year',\n MM: 'month',\n DD: 'day',\n HH: 'hours',\n hh: 'hours',\n mm: 'minutes',\n ss: 'seconds',\n A: 'ampm',\n a: 'ampm',\n};\n\n/**\n * Walk a token-format string and produce a {@link SegmentMap}, or `null` if\n * the format contains any variable-width tokens (`H`, `h`, `m`, `s`) — the\n * caller should treat that case as \"segment mode unsupported, use the input's\n * free-form text-entry fallback\".\n */\nexport function buildSegmentMap(format: string): SegmentMap | null {\n const segments: Segment[] = [];\n let cursor = 0;\n let renderedPos = 0;\n // Reset the regex's lastIndex from any previous use (it's a /g regex).\n TOKEN_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = TOKEN_REGEX.exec(format)) !== null) {\n const token = match[0];\n\n // Reject variable / odd-width tokens — they render an unpredictable number\n // of characters, which would break fixed segment boundaries.\n if (\n token === 'H' ||\n token === 'h' ||\n token === 'm' ||\n token === 's' ||\n token === 'M' ||\n token === 'D' ||\n token === 'Y' ||\n token === 'YYY'\n ) {\n return null;\n }\n\n // Capture any literal text between the previous cursor and this match.\n if (match.index > cursor) {\n const literal = format.slice(cursor, match.index);\n segments.push({\n kind: 'literal',\n token: literal,\n start: renderedPos,\n end: renderedPos + literal.length,\n });\n renderedPos += literal.length;\n }\n\n const kind = KIND_BY_TOKEN[token];\n const width = tokenWidth(token);\n const seg: Segment = {\n kind,\n token,\n start: renderedPos,\n end: renderedPos + width,\n };\n if (kind === 'hours') seg.hourFormat = token === 'hh' ? '12' : '24';\n segments.push(seg);\n\n renderedPos += width;\n cursor = match.index + token.length;\n }\n\n // Trailing literal after the final token.\n if (cursor < format.length) {\n const literal = format.slice(cursor);\n segments.push({\n kind: 'literal',\n token: literal,\n start: renderedPos,\n end: renderedPos + literal.length,\n });\n }\n\n const editable: number[] = [];\n for (let i = 0; i < segments.length; i++) {\n if (segments[i].kind !== 'literal') editable.push(i);\n }\n // Defensive: a format with no editable token is not segment-editable.\n if (editable.length === 0) return null;\n return { segments, editable };\n}\n\n// ---------------------------------------------------------------------------\n// Arithmetic helpers\n// ---------------------------------------------------------------------------\n\nconst wrap = (n: number, max: number): number => ((n % max) + max) % max;\nconst clamp = (n: number, min: number, max: number): number =>\n Math.max(min, Math.min(max, n));\n\n/**\n * Number of days in the month of `d` (handles leap Februarys). Built on\n * `makeDate`, so a year below 100 keeps its own leap rule.\n */\nconst daysInMonth = (d: Date): number =>\n makeDate(d.getFullYear(), d.getMonth() + 1, 0).getDate();\n\n/**\n * Returns a new Date with the given segment incremented (`delta` = +1 or -1).\n * Wraps at segment boundaries: year is unbounded, month 0↔11 (in place, no\n * year roll), day within the current month's length, hours-24 0↔23, hours-12\n * 1↔12, minutes/seconds 0↔59, am/pm toggles. Day is re-clamped after a\n * month/year change (Jan 31 → Feb 28/29). `isPm` is the *current* meridiem\n * when editing a 12h hour segment so we preserve it across the increment;\n * date segments ignore it.\n */\nexport function incrementSegmentValue(\n segment: Segment,\n currentDate: Date,\n delta: number,\n isPm: boolean\n): Date {\n const next = new Date(currentDate);\n switch (segment.kind) {\n case 'year':\n // Unbounded ±1; addYears clamps Feb 29 → Feb 28 on non-leap targets.\n return addYears(next, delta);\n case 'month': {\n // In-place wrap Jan↔Dec without rolling the year, then clamp the day to\n // the new month's length (e.g. Jan 31 → Feb → day 28/29).\n const day = next.getDate();\n const m0 = wrap(next.getMonth() + delta, 12);\n next.setDate(1);\n next.setMonth(m0);\n next.setDate(Math.min(day, daysInMonth(next)));\n return next;\n }\n case 'day': {\n // Wrap within the current month's day count.\n const dim = daysInMonth(next);\n next.setDate(wrap(next.getDate() - 1 + delta, dim) + 1);\n return next;\n }\n case 'hours': {\n if (segment.hourFormat === '12') {\n const h = next.getHours();\n const displayed = h % 12 === 0 ? 12 : h % 12; // 1..12\n // Move within 1..12 and preserve the current AM/PM.\n const nextDisplayed = wrap(displayed - 1 + delta, 12) + 1;\n const next24 = isPm ? (nextDisplayed % 12) + 12 : nextDisplayed % 12;\n next.setHours(next24);\n } else {\n next.setHours(wrap(next.getHours() + delta, 24));\n }\n return next;\n }\n case 'minutes':\n next.setMinutes(wrap(next.getMinutes() + delta, 60));\n return next;\n case 'seconds':\n next.setSeconds(wrap(next.getSeconds() + delta, 60));\n return next;\n case 'ampm':\n // Toggle by shifting 12 hours in either direction.\n next.setHours((next.getHours() + 12) % 24);\n return next;\n default:\n return next;\n }\n}\n\n/**\n * Apply a buffered string of typed digits to the active segment. Returns the\n * updated Date plus an `advance` flag — `true` when the buffer is full (its\n * token width) or when the first digit alone forecloses any valid multi-digit\n * completion (e.g., first digit `3` for hours-24 since 30+ is out of range, or\n * `2` for month since there is no month 20+).\n *\n * Special cases: a leading `'0'` is held without committing for hours-12,\n * month, and day (00 isn't a valid display value for any of them) — the buffer\n * must reach `'0X'` first. Month/day writes clamp to range and re-clamp the\n * day to the month's length; year writes re-clamp the day across leap-year\n * boundaries.\n */\nexport function setSegmentValue(\n segment: Segment,\n currentDate: Date,\n rawDigits: string,\n isPm: boolean\n): { date: Date; advance: boolean } {\n if (rawDigits.length === 0) return { date: currentDate, advance: false };\n const value = parseInt(rawDigits, 10);\n if (Number.isNaN(value)) return { date: currentDate, advance: false };\n const next = new Date(currentDate);\n switch (segment.kind) {\n case 'year': {\n // YYYY buffers 4 digits; YY buffers 2 (mapped into the 2000s).\n const full = segment.token === 'YYYY';\n const maxLen = full ? 4 : 2;\n const yr = full ? value : 2000 + (value % 100);\n // Set day to 1 before changing the year so a Feb-29 source doesn't roll\n // into March on a non-leap target; then restore the clamped day.\n const day = next.getDate();\n next.setDate(1);\n next.setFullYear(yr);\n next.setDate(Math.min(day, daysInMonth(next)));\n return { date: next, advance: rawDigits.length >= maxLen };\n }\n case 'month': {\n if (rawDigits === '0') {\n // Hold: 00 is invalid; wait for the second digit (01..09).\n return { date: currentDate, advance: false };\n }\n const clamped = clamp(value, 1, 12);\n const day = next.getDate();\n next.setDate(1);\n next.setMonth(clamped - 1);\n next.setDate(Math.min(day, daysInMonth(next)));\n // Advance when buffer is full, or first digit >=2 (no month 20+). First\n // digit 1 still waits for 10/11/12.\n const advance = rawDigits.length >= 2 || value >= 2;\n return { date: next, advance };\n }\n case 'day': {\n if (rawDigits === '0') {\n // Hold: 00 is invalid; wait for the second digit (01..09).\n return { date: currentDate, advance: false };\n }\n const clamped = clamp(value, 1, daysInMonth(next));\n next.setDate(clamped);\n // Advance when buffer is full, or first digit >=4 (no day 40+). First\n // digit 3 still waits for 30/31.\n const advance = rawDigits.length >= 2 || value >= 4;\n return { date: next, advance };\n }\n case 'hours': {\n if (segment.hourFormat === '12') {\n if (rawDigits === '0') {\n // Don't commit yet; wait for the second digit (01..09 are valid).\n return { date: currentDate, advance: false };\n }\n const clamped = clamp(value, 1, 12);\n const h24 = isPm ? (clamped % 12) + 12 : clamped % 12;\n next.setHours(h24);\n // Advance when the buffer is full, or when no valid 2-digit\n // completion starting with this digit exists. For 12h: only 0 and 1\n // can be the first of a 2-digit value (giving 01..09 and 10..12);\n // any other first digit completes the segment.\n const advance = rawDigits.length >= 2 || value >= 2;\n return { date: next, advance };\n }\n // 24h: valid range 0..23.\n const clamped = clamp(value, 0, 23);\n next.setHours(clamped);\n // Advance when buffer is full, or when first digit is 3..9 (since\n // 30..99 are all out of range). First digits 0, 1, 2 can still accept\n // a second digit.\n const advance = rawDigits.length >= 2 || value >= 3;\n return { date: next, advance };\n }\n case 'minutes': {\n const clamped = clamp(value, 0, 59);\n next.setMinutes(clamped);\n // Advance when buffer full, or first digit 6..9 (can't form 60..99).\n const advance = rawDigits.length >= 2 || value >= 6;\n return { date: next, advance };\n }\n case 'seconds': {\n const clamped = clamp(value, 0, 59);\n next.setSeconds(clamped);\n const advance = rawDigits.length >= 2 || value >= 6;\n return { date: next, advance };\n }\n default:\n return { date: currentDate, advance: false };\n }\n}\n\n/** Force the meridiem of `currentDate` to AM (isPm=false) or PM (true). */\nexport function setAmPm(currentDate: Date, isPm: boolean): Date {\n const next = new Date(currentDate);\n const h = next.getHours();\n if (isPm && h < 12) next.setHours(h + 12);\n if (!isPm && h >= 12) next.setHours(h - 12);\n return next;\n}\n\n/** Map a caret position into the index of the segment that contains it. */\nexport function segmentIndexAtCaret(\n map: SegmentMap,\n caret: number\n): number | null {\n // Prefer an editable segment that strictly contains the caret; otherwise\n // the nearest editable segment by char distance.\n for (const idx of map.editable) {\n const s = map.segments[idx];\n if (caret >= s.start && caret <= s.end) return idx;\n }\n let bestIdx = map.editable[0] ?? null;\n let bestDist = Infinity;\n for (const idx of map.editable) {\n const s = map.segments[idx];\n const dist = Math.min(Math.abs(caret - s.start), Math.abs(caret - s.end));\n if (dist < bestDist) {\n bestDist = dist;\n bestIdx = idx;\n }\n }\n return bestIdx;\n}\n"],"names":["wrap"],"mappings":";;;AAAA;;;;;;;;;;;;AAYG;AAgCH;AACA;AACA;AACA;AACA;AACA,MAAM,WAAW,GAAG,kDAAkD;AAEtE;AACA;AACA,MAAM,UAAU,GAAG,CAAC,KAAa,MAAc,KAAK,KAAK,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;AAExE,MAAM,aAAa,GAAgC;AACjD,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,EAAE,EAAE,MAAM;AACV,IAAA,EAAE,EAAE,OAAO;AACX,IAAA,EAAE,EAAE,KAAK;AACT,IAAA,EAAE,EAAE,OAAO;AACX,IAAA,EAAE,EAAE,OAAO;AACX,IAAA,EAAE,EAAE,SAAS;AACb,IAAA,EAAE,EAAE,SAAS;AACb,IAAA,CAAC,EAAE,MAAM;AACT,IAAA,CAAC,EAAE,MAAM;CACV;AAED;;;;;AAKG;AACG,SAAU,eAAe,CAAC,MAAc,EAAA;IAC5C,MAAM,QAAQ,GAAc,EAAE;IAC9B,IAAI,MAAM,GAAG,CAAC;IACd,IAAI,WAAW,GAAG,CAAC;;AAEnB,IAAA,WAAW,CAAC,SAAS,GAAG,CAAC;AACzB,IAAA,IAAI,KAA6B;AACjC,IAAA,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE;AAClD,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;;;QAItB,IACE,KAAK,KAAK,GAAG;AACb,YAAA,KAAK,KAAK,GAAG;AACb,YAAA,KAAK,KAAK,GAAG;AACb,YAAA,KAAK,KAAK,GAAG;AACb,YAAA,KAAK,KAAK,GAAG;AACb,YAAA,KAAK,KAAK,GAAG;AACb,YAAA,KAAK,KAAK,GAAG;YACb,KAAK,KAAK,KAAK,EACf;AACA,YAAA,OAAO,IAAI;QACb;;AAGA,QAAA,IAAI,KAAK,CAAC,KAAK,GAAG,MAAM,EAAE;AACxB,YAAA,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC;YACjD,QAAQ,CAAC,IAAI,CAAC;AACZ,gBAAA,IAAI,EAAE,SAAS;AACf,gBAAA,KAAK,EAAE,OAAO;AACd,gBAAA,KAAK,EAAE,WAAW;AAClB,gBAAA,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM;AAClC,aAAA,CAAC;AACF,YAAA,WAAW,IAAI,OAAO,CAAC,MAAM;QAC/B;AAEA,QAAA,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC;AACjC,QAAA,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;AAC/B,QAAA,MAAM,GAAG,GAAY;YACnB,IAAI;YACJ,KAAK;AACL,YAAA,KAAK,EAAE,WAAW;YAClB,GAAG,EAAE,WAAW,GAAG,KAAK;SACzB;QACD,IAAI,IAAI,KAAK,OAAO;AAAE,YAAA,GAAG,CAAC,UAAU,GAAG,KAAK,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;AACnE,QAAA,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;QAElB,WAAW,IAAI,KAAK;QACpB,MAAM,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM;IACrC;;AAGA,IAAA,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE;QAC1B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QACpC,QAAQ,CAAC,IAAI,CAAC;AACZ,YAAA,IAAI,EAAE,SAAS;AACf,YAAA,KAAK,EAAE,OAAO;AACd,YAAA,KAAK,EAAE,WAAW;AAClB,YAAA,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM;AAClC,SAAA,CAAC;IACJ;IAEA,MAAM,QAAQ,GAAa,EAAE;AAC7B,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACxC,QAAA,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS;AAAE,YAAA,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACtD;;AAEA,IAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;AAAE,QAAA,OAAO,IAAI;AACtC,IAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE;AAC/B;AAEA;AACA;AACA;AAEA,MAAMA,MAAI,GAAG,CAAC,CAAS,EAAE,GAAW,KAAa,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG;AACxE,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,GAAW,KAChD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AAEjC;;;AAGG;AACH,MAAM,WAAW,GAAG,CAAC,CAAO,KAC1B,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE;AAE1D;;;;;;;;AAQG;AACG,SAAU,qBAAqB,CACnC,OAAgB,EAChB,WAAiB,EACjB,KAAa,EACb,IAAa,EAAA;AAEb,IAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC;AAClC,IAAA,QAAQ,OAAO,CAAC,IAAI;AAClB,QAAA,KAAK,MAAM;;AAET,YAAA,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;QAC9B,KAAK,OAAO,EAAE;;;AAGZ,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,YAAA,MAAM,EAAE,GAAGA,MAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC;AAC5C,YAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACf,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;AACjB,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,YAAA,OAAO,IAAI;QACb;QACA,KAAK,KAAK,EAAE;;AAEV,YAAA,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC;AAC7B,YAAA,IAAI,CAAC,OAAO,CAACA,MAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AACvD,YAAA,OAAO,IAAI;QACb;QACA,KAAK,OAAO,EAAE;AACZ,YAAA,IAAI,OAAO,CAAC,UAAU,KAAK,IAAI,EAAE;AAC/B,gBAAA,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE;AACzB,gBAAA,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;;AAE7C,gBAAA,MAAM,aAAa,GAAGA,MAAI,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC;AACzD,gBAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,aAAa,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,GAAG,EAAE;AACpE,gBAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACvB;iBAAO;AACL,gBAAA,IAAI,CAAC,QAAQ,CAACA,MAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC;YAClD;AACA,YAAA,OAAO,IAAI;QACb;AACA,QAAA,KAAK,SAAS;AACZ,YAAA,IAAI,CAAC,UAAU,CAACA,MAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC;AACpD,YAAA,OAAO,IAAI;AACb,QAAA,KAAK,SAAS;AACZ,YAAA,IAAI,CAAC,UAAU,CAACA,MAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC;AACpD,YAAA,OAAO,IAAI;AACb,QAAA,KAAK,MAAM;;AAET,YAAA,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAC1C,YAAA,OAAO,IAAI;AACb,QAAA;AACE,YAAA,OAAO,IAAI;;AAEjB;AAEA;;;;;;;;;;;;AAYG;AACG,SAAU,eAAe,CAC7B,OAAgB,EAChB,WAAiB,EACjB,SAAiB,EACjB,IAAa,EAAA;AAEb,IAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE;IACxE,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;AACrC,IAAA,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE;AACrE,IAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC;AAClC,IAAA,QAAQ,OAAO,CAAC,IAAI;QAClB,KAAK,MAAM,EAAE;;AAEX,YAAA,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,KAAK,MAAM;YACrC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC;AAC3B,YAAA,MAAM,EAAE,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,GAAG,CAAC;;;AAG9C,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,YAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACf,YAAA,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;AACpB,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,YAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,MAAM,IAAI,MAAM,EAAE;QAC5D;QACA,KAAK,OAAO,EAAE;AACZ,YAAA,IAAI,SAAS,KAAK,GAAG,EAAE;;gBAErB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE;YAC9C;YACA,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;AACnC,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,YAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACf,YAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC;AAC1B,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;;;YAG9C,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;AACnD,YAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAChC;QACA,KAAK,KAAK,EAAE;AACV,YAAA,IAAI,SAAS,KAAK,GAAG,EAAE;;gBAErB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE;YAC9C;AACA,YAAA,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;AAClD,YAAA,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;;;YAGrB,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;AACnD,YAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAChC;QACA,KAAK,OAAO,EAAE;AACZ,YAAA,IAAI,OAAO,CAAC,UAAU,KAAK,IAAI,EAAE;AAC/B,gBAAA,IAAI,SAAS,KAAK,GAAG,EAAE;;oBAErB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE;gBAC9C;gBACA,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;AACnC,gBAAA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,EAAE;AACrD,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;;;;;gBAKlB,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;AACnD,gBAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;YAChC;;YAEA,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;AACnC,YAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;;;;YAItB,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;AACnD,YAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAChC;QACA,KAAK,SAAS,EAAE;YACd,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;AACnC,YAAA,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;;YAExB,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;AACnD,YAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAChC;QACA,KAAK,SAAS,EAAE;YACd,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;AACnC,YAAA,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YACxB,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;AACnD,YAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAChC;AACA,QAAA;YACE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE;;AAElD;AAEA;AACM,SAAU,OAAO,CAAC,WAAiB,EAAE,IAAa,EAAA;AACtD,IAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC;AAClC,IAAA,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE;AACzB,IAAA,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE;AAAE,QAAA,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;AACzC,IAAA,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE;AAAE,QAAA,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;AAC3C,IAAA,OAAO,IAAI;AACb;AAEA;AACM,SAAU,mBAAmB,CACjC,GAAe,EACf,KAAa,EAAA;;;AAIb,IAAA,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE;QAC9B,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QAC3B,IAAI,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,GAAG;AAAE,YAAA,OAAO,GAAG;IACpD;IACA,IAAI,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI;IACrC,IAAI,QAAQ,GAAG,QAAQ;AACvB,IAAA,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE;QAC9B,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC3B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AACzE,QAAA,IAAI,IAAI,GAAG,QAAQ,EAAE;YACnB,QAAQ,GAAG,IAAI;YACf,OAAO,GAAG,GAAG;QACf;IACF;AACA,IAAA,OAAO,OAAO;AAChB;;"}
|
|
1
|
+
{"version":3,"file":"segmentMap.js","sources":["../../../../src/form/_pickerInternals/segmentMap.ts"],"sourcesContent":["/**\n * Segment-map utility for manual keyboard entry on a date / time picker input.\n * Given a token-format string like `'YYYY-MM-DD'`, `'HH:mm:ss'`, `'hh:mm A'`,\n * or a combined `'YYYY-MM-DD HH:mm'`, we compute the character ranges of each\n * editable segment in the formatted output, plus arithmetic helpers\n * (increment / digit-set) for each kind.\n *\n * Variable-width tokens (`Y`, `YYY`, `M`, `D`, `H`, `h`, `m`, `s`) cause the\n * renderer to emit output of unpredictable width depending on value, which\n * would shift segment boundaries between renders and break the selection.\n * `buildSegmentMap` returns `null` for any format containing those, signalling\n * the caller to fall back to free-form text entry.\n */\n\nimport { addYears, makeDate } from './dateUtils';\n\nexport type SegmentKind =\n | 'year'\n | 'month'\n | 'day'\n | 'hours'\n | 'minutes'\n | 'seconds'\n | 'ampm'\n | 'literal';\n\nexport interface Segment {\n kind: SegmentKind;\n /** Source token (e.g., `'HH'`) for editable segments; literal text for `'literal'`. */\n token: string;\n /** Inclusive char index into the formatted-string output. */\n start: number;\n /** Exclusive char index. */\n end: number;\n /** Populated only when `kind === 'hours'`. */\n hourFormat?: '12' | '24';\n}\n\nexport interface SegmentMap {\n segments: Segment[];\n /** Indices of non-literal segments, left to right. */\n editable: number[];\n}\n\n// Match longest tokens first so `HH` doesn't collapse to two `H`s and `YYYY`\n// doesn't collapse to `YY` + `YY`. The single-char and odd-width variants\n// (`Y`, `YYY`, `M`, `D`, `H`, `h`, `m`, `s`) are matched only so they can be\n// explicitly rejected below — otherwise a format like `'YYY-MM'` would\n// silently mis-tokenize as `YY` + a stray `Y`.\nconst TOKEN_REGEX = /YYYY|YYY|YY|Y|MM|M|DD|D|HH|hh|mm|ss|H|h|m|s|A|a/g;\n\n// Fixed-width tokens render the same number of chars on every value. All are 2\n// wide except the 4-digit year.\nconst tokenWidth = (token: string): number => (token === 'YYYY' ? 4 : 2);\n\nconst KIND_BY_TOKEN: Record<string, SegmentKind> = {\n YYYY: 'year',\n YY: 'year',\n MM: 'month',\n DD: 'day',\n HH: 'hours',\n hh: 'hours',\n mm: 'minutes',\n ss: 'seconds',\n A: 'ampm',\n a: 'ampm',\n};\n\n/**\n * Walk a token-format string and produce a {@link SegmentMap}, or `null` if\n * the format contains any variable-width tokens (`H`, `h`, `m`, `s`) — the\n * caller should treat that case as \"segment mode unsupported, use the input's\n * free-form text-entry fallback\".\n */\nexport function buildSegmentMap(format: string): SegmentMap | null {\n const segments: Segment[] = [];\n let cursor = 0;\n let renderedPos = 0;\n // Reset the regex's lastIndex from any previous use (it's a /g regex).\n TOKEN_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = TOKEN_REGEX.exec(format)) !== null) {\n const token = match[0];\n\n // Reject variable / odd-width tokens — they render an unpredictable number\n // of characters, which would break fixed segment boundaries.\n if (\n token === 'H' ||\n token === 'h' ||\n token === 'm' ||\n token === 's' ||\n token === 'M' ||\n token === 'D' ||\n token === 'Y' ||\n token === 'YYY'\n ) {\n return null;\n }\n\n // Capture any literal text between the previous cursor and this match.\n if (match.index > cursor) {\n const literal = format.slice(cursor, match.index);\n segments.push({\n kind: 'literal',\n token: literal,\n start: renderedPos,\n end: renderedPos + literal.length,\n });\n renderedPos += literal.length;\n }\n\n const kind = KIND_BY_TOKEN[token];\n const width = tokenWidth(token);\n const seg: Segment = {\n kind,\n token,\n start: renderedPos,\n end: renderedPos + width,\n };\n if (kind === 'hours') seg.hourFormat = token === 'hh' ? '12' : '24';\n segments.push(seg);\n\n renderedPos += width;\n cursor = match.index + token.length;\n }\n\n // Trailing literal after the final token.\n if (cursor < format.length) {\n const literal = format.slice(cursor);\n segments.push({\n kind: 'literal',\n token: literal,\n start: renderedPos,\n end: renderedPos + literal.length,\n });\n }\n\n const editable: number[] = [];\n for (let i = 0; i < segments.length; i++) {\n if (segments[i].kind !== 'literal') editable.push(i);\n }\n // Defensive: a format with no editable token is not segment-editable.\n if (editable.length === 0) return null;\n return { segments, editable };\n}\n\n// ---------------------------------------------------------------------------\n// Arithmetic helpers\n// ---------------------------------------------------------------------------\n\nconst wrap = (n: number, max: number): number => ((n % max) + max) % max;\nconst clamp = (n: number, min: number, max: number): number =>\n Math.max(min, Math.min(max, n));\n\n/**\n * Number of days in the month of `d` (handles leap Februarys). Built on\n * `makeDate`, so a year below 100 keeps its own leap rule.\n */\nconst daysInMonth = (d: Date): number =>\n makeDate(d.getFullYear(), d.getMonth() + 1, 0).getDate();\n\n/**\n * Returns a new Date with the given segment incremented (`delta` = +1 or -1).\n * Wraps at segment boundaries: year is unbounded, month 0↔11 (in place, no\n * year roll), day within the current month's length, hours-24 0↔23, hours-12\n * 1↔12, minutes/seconds 0↔59, am/pm toggles. Day is re-clamped after a\n * month/year change (Jan 31 → Feb 28/29). `isPm` is the *current* meridiem\n * when editing a 12h hour segment so we preserve it across the increment;\n * date segments ignore it.\n */\nexport function incrementSegmentValue(\n segment: Segment,\n currentDate: Date,\n delta: number,\n isPm: boolean\n): Date {\n const next = new Date(currentDate);\n switch (segment.kind) {\n case 'year':\n // Unbounded ±1; addYears clamps Feb 29 → Feb 28 on non-leap targets.\n return addYears(next, delta);\n case 'month': {\n // In-place wrap Jan↔Dec without rolling the year, then clamp the day to\n // the new month's length (e.g. Jan 31 → Feb → day 28/29).\n const day = next.getDate();\n const m0 = wrap(next.getMonth() + delta, 12);\n next.setDate(1);\n next.setMonth(m0);\n next.setDate(Math.min(day, daysInMonth(next)));\n return next;\n }\n case 'day': {\n // Wrap within the current month's day count.\n const dim = daysInMonth(next);\n next.setDate(wrap(next.getDate() - 1 + delta, dim) + 1);\n return next;\n }\n case 'hours': {\n if (segment.hourFormat === '12') {\n const h = next.getHours();\n const displayed = h % 12 === 0 ? 12 : h % 12; // 1..12\n // Move within 1..12 and preserve the current AM/PM.\n const nextDisplayed = wrap(displayed - 1 + delta, 12) + 1;\n const next24 = isPm ? (nextDisplayed % 12) + 12 : nextDisplayed % 12;\n next.setHours(next24);\n } else {\n next.setHours(wrap(next.getHours() + delta, 24));\n }\n return next;\n }\n case 'minutes':\n next.setMinutes(wrap(next.getMinutes() + delta, 60));\n return next;\n case 'seconds':\n next.setSeconds(wrap(next.getSeconds() + delta, 60));\n return next;\n case 'ampm':\n // Toggle by shifting 12 hours in either direction.\n next.setHours((next.getHours() + 12) % 24);\n return next;\n default:\n return next;\n }\n}\n\n/**\n * Apply a buffered string of typed digits to the active segment. Returns the\n * updated Date plus an `advance` flag — `true` when the buffer is full (its\n * token width) or when the first digit alone forecloses any valid multi-digit\n * completion (e.g., first digit `3` for hours-24 since 30+ is out of range, or\n * `2` for month since there is no month 20+).\n *\n * Special cases: a leading `'0'` is held without committing for hours-12,\n * month, and day (00 isn't a valid display value for any of them) — the buffer\n * must reach `'0X'` first. Month/day writes clamp to range and re-clamp the\n * day to the month's length; year writes re-clamp the day across leap-year\n * boundaries.\n */\nexport function setSegmentValue(\n segment: Segment,\n currentDate: Date,\n rawDigits: string,\n isPm: boolean\n): { date: Date; advance: boolean } {\n if (rawDigits.length === 0) return { date: currentDate, advance: false };\n const value = parseInt(rawDigits, 10);\n if (Number.isNaN(value)) return { date: currentDate, advance: false };\n const next = new Date(currentDate);\n switch (segment.kind) {\n case 'year': {\n // YYYY buffers 4 digits; YY buffers 2 (mapped into the 2000s).\n const full = segment.token === 'YYYY';\n const maxLen = full ? 4 : 2;\n const yr = full ? value : 2000 + (value % 100);\n // Set day to 1 before changing the year so a Feb-29 source doesn't roll\n // into March on a non-leap target; then restore the clamped day.\n const day = next.getDate();\n next.setDate(1);\n next.setFullYear(yr);\n next.setDate(Math.min(day, daysInMonth(next)));\n return { date: next, advance: rawDigits.length >= maxLen };\n }\n case 'month': {\n if (rawDigits === '0') {\n // Hold: 00 is invalid; wait for the second digit (01..09).\n return { date: currentDate, advance: false };\n }\n const clamped = clamp(value, 1, 12);\n const day = next.getDate();\n next.setDate(1);\n next.setMonth(clamped - 1);\n next.setDate(Math.min(day, daysInMonth(next)));\n // Advance when buffer is full, or first digit >=2 (no month 20+). First\n // digit 1 still waits for 10/11/12.\n const advance = rawDigits.length >= 2 || value >= 2;\n return { date: next, advance };\n }\n case 'day': {\n if (rawDigits === '0') {\n // Hold: 00 is invalid; wait for the second digit (01..09).\n return { date: currentDate, advance: false };\n }\n const clamped = clamp(value, 1, daysInMonth(next));\n next.setDate(clamped);\n // Advance when buffer is full, or first digit >=4 (no day 40+). First\n // digit 3 still waits for 30/31.\n const advance = rawDigits.length >= 2 || value >= 4;\n return { date: next, advance };\n }\n case 'hours': {\n if (segment.hourFormat === '12') {\n if (rawDigits === '0') {\n // Don't commit yet; wait for the second digit (01..09 are valid).\n return { date: currentDate, advance: false };\n }\n const clamped = clamp(value, 1, 12);\n const h24 = isPm ? (clamped % 12) + 12 : clamped % 12;\n next.setHours(h24);\n // Advance when the buffer is full, or when no valid 2-digit\n // completion starting with this digit exists. For 12h: only 0 and 1\n // can be the first of a 2-digit value (giving 01..09 and 10..12);\n // any other first digit completes the segment.\n const advance = rawDigits.length >= 2 || value >= 2;\n return { date: next, advance };\n }\n // 24h: valid range 0..23.\n const clamped = clamp(value, 0, 23);\n next.setHours(clamped);\n // Advance when buffer is full, or when first digit is 3..9 (since\n // 30..99 are all out of range). First digits 0, 1, 2 can still accept\n // a second digit.\n const advance = rawDigits.length >= 2 || value >= 3;\n return { date: next, advance };\n }\n case 'minutes': {\n const clamped = clamp(value, 0, 59);\n next.setMinutes(clamped);\n // Advance when buffer full, or first digit 6..9 (can't form 60..99).\n const advance = rawDigits.length >= 2 || value >= 6;\n return { date: next, advance };\n }\n case 'seconds': {\n const clamped = clamp(value, 0, 59);\n next.setSeconds(clamped);\n const advance = rawDigits.length >= 2 || value >= 6;\n return { date: next, advance };\n }\n default:\n return { date: currentDate, advance: false };\n }\n}\n\n/** Force the meridiem of `currentDate` to AM (isPm=false) or PM (true). */\nexport function setAmPm(currentDate: Date, isPm: boolean): Date {\n const next = new Date(currentDate);\n const h = next.getHours();\n if (isPm && h < 12) next.setHours(h + 12);\n if (!isPm && h >= 12) next.setHours(h - 12);\n return next;\n}\n\n/** Map a caret position into the index of the segment that contains it. */\nexport function segmentIndexAtCaret(\n map: SegmentMap,\n caret: number\n): number | null {\n // Prefer an editable segment that strictly contains the caret; otherwise\n // the nearest editable segment by char distance.\n for (const idx of map.editable) {\n const s = map.segments[idx];\n if (caret >= s.start && caret <= s.end) return idx;\n }\n let bestIdx = map.editable[0] ?? null;\n let bestDist = Infinity;\n for (const idx of map.editable) {\n const s = map.segments[idx];\n const dist = Math.min(Math.abs(caret - s.start), Math.abs(caret - s.end));\n if (dist < bestDist) {\n bestDist = dist;\n bestIdx = idx;\n }\n }\n return bestIdx;\n}\n"],"names":["wrap","clamp"],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
// INTERNAL: deliberately not exported from src/index.ts.
|
|
3
|
+
//
|
|
4
|
+
// The arithmetic behind Splitter. Every size is a percentage of the length
|
|
5
|
+
// the panes share, which is the splitter's length less its handles, and a
|
|
6
|
+
// layout always adds up to 100.
|
|
7
|
+
// Rounding leaves sizes a hair off, so anything this close counts as equal.
|
|
8
|
+
const EPS = 1e-6;
|
|
9
|
+
const clamp = (value, low, high) => Math.min(Math.max(value, low), high);
|
|
10
|
+
/**
|
|
11
|
+
* A limit in percent of `length` pixels. A number or a `%` is already one. A
|
|
12
|
+
* `px` or `rem` length needs the length the panes share, and without it
|
|
13
|
+
* there's no answer yet, so it's `null`. Anything else is `null` too.
|
|
14
|
+
*/
|
|
15
|
+
function limitToPercent(limit, length, remPx) {
|
|
16
|
+
if (limit === undefined)
|
|
17
|
+
return null;
|
|
18
|
+
if (typeof limit === 'number')
|
|
19
|
+
return limit;
|
|
20
|
+
const match = /^\s*(\d*\.?\d+)\s*(px|rem|%)?\s*$/.exec(limit);
|
|
21
|
+
if (!match)
|
|
22
|
+
return null;
|
|
23
|
+
const value = parseFloat(match[1]);
|
|
24
|
+
const unit = match[2] ?? '%';
|
|
25
|
+
if (unit === '%')
|
|
26
|
+
return value;
|
|
27
|
+
if (!length)
|
|
28
|
+
return null;
|
|
29
|
+
return ((unit === 'rem' ? value * remPx : value) / length) * 100;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The sizes panes start at: each its `defaultSize`, and the ones without
|
|
33
|
+
* one sharing what's left equally. When they all have one, or those that do
|
|
34
|
+
* take more than 100, the given ones are scaled to fit.
|
|
35
|
+
*/
|
|
36
|
+
function defaultSizes(defaults) {
|
|
37
|
+
const given = defaults.reduce((sum, d) => sum + (d ?? 0), 0);
|
|
38
|
+
const free = defaults.filter(d => d === undefined).length;
|
|
39
|
+
if (free === 0 || given > 100) {
|
|
40
|
+
const scale = given > 0 ? 100 / given : 0;
|
|
41
|
+
return defaults.map(d => d === undefined ? 0 : scale ? d * scale : 100 / defaults.length);
|
|
42
|
+
}
|
|
43
|
+
const share = (100 - given) / free;
|
|
44
|
+
return defaults.map(d => (d === undefined ? share : d));
|
|
45
|
+
}
|
|
46
|
+
/** The range a pane can take in a layout: zero when it's shut. */
|
|
47
|
+
const rangeOf = (bound, size) => bound.collapsible && size <= EPS
|
|
48
|
+
? { low: 0, high: 0 }
|
|
49
|
+
: { low: bound.min, high: bound.max };
|
|
50
|
+
/**
|
|
51
|
+
* Moves each pane into its limits, taking what it needs from the nearest
|
|
52
|
+
* panes with room to give, or giving what it has too much of to the nearest
|
|
53
|
+
* with room to take. A shut pane stays shut. Limits that can't all hold are
|
|
54
|
+
* met as far as they can be.
|
|
55
|
+
*/
|
|
56
|
+
function fitSizes(sizes, bounds) {
|
|
57
|
+
const next = [...sizes];
|
|
58
|
+
const n = next.length;
|
|
59
|
+
// Nearest first, so a change stays as local as it can.
|
|
60
|
+
const byDistance = (i) => next
|
|
61
|
+
.map((_, j) => j)
|
|
62
|
+
.filter(j => j !== i)
|
|
63
|
+
.sort((x, y) => Math.abs(x - i) - Math.abs(y - i) || x - y);
|
|
64
|
+
for (let pass = 0; pass < n * 2; pass++) {
|
|
65
|
+
let moved = false;
|
|
66
|
+
for (let i = 0; i < n; i++) {
|
|
67
|
+
const { low, high } = rangeOf(bounds[i], next[i]);
|
|
68
|
+
if (next[i] < low - EPS) {
|
|
69
|
+
let need = low - next[i];
|
|
70
|
+
for (const j of byDistance(i)) {
|
|
71
|
+
const give = Math.min(need, Math.max(0, next[j] - rangeOf(bounds[j], next[j]).low));
|
|
72
|
+
next[j] -= give;
|
|
73
|
+
next[i] += give;
|
|
74
|
+
need -= give;
|
|
75
|
+
if (give > EPS)
|
|
76
|
+
moved = true;
|
|
77
|
+
if (need <= EPS)
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else if (next[i] > high + EPS) {
|
|
82
|
+
let spare = next[i] - high;
|
|
83
|
+
for (const j of byDistance(i)) {
|
|
84
|
+
const take = Math.min(spare, Math.max(0, rangeOf(bounds[j], next[j]).high - next[j]));
|
|
85
|
+
next[j] += take;
|
|
86
|
+
next[i] -= take;
|
|
87
|
+
spare -= take;
|
|
88
|
+
if (take > EPS)
|
|
89
|
+
moved = true;
|
|
90
|
+
if (spare <= EPS)
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!moved)
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
return next;
|
|
99
|
+
}
|
|
100
|
+
/** Whether two layouts are the same, to within rounding. */
|
|
101
|
+
const sameSizes = (a, b) => a.length === b.length && a.every((size, i) => Math.abs(size - b[i]) <= EPS);
|
|
102
|
+
/**
|
|
103
|
+
* The pane a handle speaks for: the one before it, unless only the one after
|
|
104
|
+
* it can shut, so that Enter shuts the pane you'd expect.
|
|
105
|
+
*/
|
|
106
|
+
const primaryOf = (handle, bounds) => !bounds[handle].collapsible && bounds[handle + 1].collapsible
|
|
107
|
+
? handle + 1
|
|
108
|
+
: handle;
|
|
109
|
+
/**
|
|
110
|
+
* How far the pane before handle `a`'s line can go, between the two panes
|
|
111
|
+
* beside it: `low` to `high` while both stay open, and `shut` and `full`
|
|
112
|
+
* when one of them can close.
|
|
113
|
+
*/
|
|
114
|
+
function pairRange(sizes, a, bounds) {
|
|
115
|
+
const b = a + 1;
|
|
116
|
+
const total = sizes[a] + sizes[b];
|
|
117
|
+
const low = Math.max(bounds[a].min, total - bounds[b].max);
|
|
118
|
+
const high = Math.min(bounds[a].max, total - bounds[b].min);
|
|
119
|
+
return {
|
|
120
|
+
total,
|
|
121
|
+
low,
|
|
122
|
+
high,
|
|
123
|
+
// The pane before can shut if it may and the one after can take it all.
|
|
124
|
+
shut: bounds[a].collapsible && total <= bounds[b].max + EPS,
|
|
125
|
+
// The pane after can shut likewise.
|
|
126
|
+
full: bounds[b].collapsible && total <= bounds[a].max + EPS,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The layout with the line of handle `a` moved so the pane before it is
|
|
131
|
+
* `target`, within both panes' limits. A collapsible pane dragged below half
|
|
132
|
+
* its minimum shuts, and one that's shut opens at its minimum once dragged
|
|
133
|
+
* past that point.
|
|
134
|
+
*/
|
|
135
|
+
function resizePair(sizes, a, target, bounds) {
|
|
136
|
+
const b = a + 1;
|
|
137
|
+
const { total, low, high, shut, full } = pairRange(sizes, a, bounds);
|
|
138
|
+
let size;
|
|
139
|
+
if (shut && target < bounds[a].min / 2)
|
|
140
|
+
size = 0;
|
|
141
|
+
else if (full && total - target < bounds[b].min / 2)
|
|
142
|
+
size = total;
|
|
143
|
+
else if (low > high + EPS)
|
|
144
|
+
size = sizes[a];
|
|
145
|
+
else
|
|
146
|
+
size = clamp(target, low, high);
|
|
147
|
+
const next = [...sizes];
|
|
148
|
+
next[a] = size;
|
|
149
|
+
next[b] = total - size;
|
|
150
|
+
return next;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The aria value range of a handle's primary pane: zero at the bottom when
|
|
154
|
+
* it can shut, everything the pair holds at the top when the other pane can.
|
|
155
|
+
*/
|
|
156
|
+
function primaryRange(sizes, a, primary, bounds) {
|
|
157
|
+
const { total, low, high, shut, full } = pairRange(sizes, a, bounds);
|
|
158
|
+
const minA = shut ? 0 : low;
|
|
159
|
+
const maxA = full ? total : high;
|
|
160
|
+
return primary === a
|
|
161
|
+
? { now: sizes[a], min: minA, max: maxA }
|
|
162
|
+
: { now: sizes[a + 1], min: total - maxA, max: total - minA };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export { defaultSizes, fitSizes, limitToPercent, pairRange, primaryOf, primaryRange, resizePair, sameSizes };
|
|
166
|
+
//# sourceMappingURL=splitterLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitterLayout.js","sources":["../../../src/helpers/splitterLayout.ts"],"sourcesContent":["// INTERNAL: deliberately not exported from src/index.ts.\n//\n// The arithmetic behind Splitter. Every size is a percentage of the length\n// the panes share, which is the splitter's length less its handles, and a\n// layout always adds up to 100.\n\n/** What one pane may be: its limits in percent, and whether it can shut. */\nexport interface PaneBounds {\n min: number;\n max: number;\n collapsible: boolean;\n}\n\n/** A limit as written: a percentage, or a CSS length in px, rem or %. */\nexport type SplitterLimit = number | string;\n\n// Rounding leaves sizes a hair off, so anything this close counts as equal.\nconst EPS = 1e-6;\n\nconst clamp = (value: number, low: number, high: number) =>\n Math.min(Math.max(value, low), high);\n\n/**\n * A limit in percent of `length` pixels. A number or a `%` is already one. A\n * `px` or `rem` length needs the length the panes share, and without it\n * there's no answer yet, so it's `null`. Anything else is `null` too.\n */\nexport function limitToPercent(\n limit: SplitterLimit | undefined,\n length: number | null,\n remPx: number\n): number | null {\n if (limit === undefined) return null;\n if (typeof limit === 'number') return limit;\n const match = /^\\s*(\\d*\\.?\\d+)\\s*(px|rem|%)?\\s*$/.exec(limit);\n if (!match) return null;\n const value = parseFloat(match[1]);\n const unit = match[2] ?? '%';\n if (unit === '%') return value;\n if (!length) return null;\n return ((unit === 'rem' ? value * remPx : value) / length) * 100;\n}\n\n/**\n * The sizes panes start at: each its `defaultSize`, and the ones without\n * one sharing what's left equally. When they all have one, or those that do\n * take more than 100, the given ones are scaled to fit.\n */\nexport function defaultSizes(defaults: (number | undefined)[]): number[] {\n const given = defaults.reduce<number>((sum, d) => sum + (d ?? 0), 0);\n const free = defaults.filter(d => d === undefined).length;\n if (free === 0 || given > 100) {\n const scale = given > 0 ? 100 / given : 0;\n return defaults.map(d =>\n d === undefined ? 0 : scale ? d * scale : 100 / defaults.length\n );\n }\n const share = (100 - given) / free;\n return defaults.map(d => (d === undefined ? share : d));\n}\n\n/** The range a pane can take in a layout: zero when it's shut. */\nconst rangeOf = (bound: PaneBounds, size: number) =>\n bound.collapsible && size <= EPS\n ? { low: 0, high: 0 }\n : { low: bound.min, high: bound.max };\n\n/**\n * Moves each pane into its limits, taking what it needs from the nearest\n * panes with room to give, or giving what it has too much of to the nearest\n * with room to take. A shut pane stays shut. Limits that can't all hold are\n * met as far as they can be.\n */\nexport function fitSizes(sizes: number[], bounds: PaneBounds[]): number[] {\n const next = [...sizes];\n const n = next.length;\n // Nearest first, so a change stays as local as it can.\n const byDistance = (i: number) =>\n next\n .map((_, j) => j)\n .filter(j => j !== i)\n .sort((x, y) => Math.abs(x - i) - Math.abs(y - i) || x - y);\n for (let pass = 0; pass < n * 2; pass++) {\n let moved = false;\n for (let i = 0; i < n; i++) {\n const { low, high } = rangeOf(bounds[i], next[i]);\n if (next[i] < low - EPS) {\n let need = low - next[i];\n for (const j of byDistance(i)) {\n const give = Math.min(\n need,\n Math.max(0, next[j] - rangeOf(bounds[j], next[j]).low)\n );\n next[j] -= give;\n next[i] += give;\n need -= give;\n if (give > EPS) moved = true;\n if (need <= EPS) break;\n }\n } else if (next[i] > high + EPS) {\n let spare = next[i] - high;\n for (const j of byDistance(i)) {\n const take = Math.min(\n spare,\n Math.max(0, rangeOf(bounds[j], next[j]).high - next[j])\n );\n next[j] += take;\n next[i] -= take;\n spare -= take;\n if (take > EPS) moved = true;\n if (spare <= EPS) break;\n }\n }\n }\n if (!moved) break;\n }\n return next;\n}\n\n/** Whether two layouts are the same, to within rounding. */\nexport const sameSizes = (a: number[], b: number[]) =>\n a.length === b.length && a.every((size, i) => Math.abs(size - b[i]) <= EPS);\n\n/**\n * The pane a handle speaks for: the one before it, unless only the one after\n * it can shut, so that Enter shuts the pane you'd expect.\n */\nexport const primaryOf = (handle: number, bounds: PaneBounds[]) =>\n !bounds[handle].collapsible && bounds[handle + 1].collapsible\n ? handle + 1\n : handle;\n\n/**\n * How far the pane before handle `a`'s line can go, between the two panes\n * beside it: `low` to `high` while both stay open, and `shut` and `full`\n * when one of them can close.\n */\nexport function pairRange(sizes: number[], a: number, bounds: PaneBounds[]) {\n const b = a + 1;\n const total = sizes[a] + sizes[b];\n const low = Math.max(bounds[a].min, total - bounds[b].max);\n const high = Math.min(bounds[a].max, total - bounds[b].min);\n return {\n total,\n low,\n high,\n // The pane before can shut if it may and the one after can take it all.\n shut: bounds[a].collapsible && total <= bounds[b].max + EPS,\n // The pane after can shut likewise.\n full: bounds[b].collapsible && total <= bounds[a].max + EPS,\n };\n}\n\n/**\n * The layout with the line of handle `a` moved so the pane before it is\n * `target`, within both panes' limits. A collapsible pane dragged below half\n * its minimum shuts, and one that's shut opens at its minimum once dragged\n * past that point.\n */\nexport function resizePair(\n sizes: number[],\n a: number,\n target: number,\n bounds: PaneBounds[]\n): number[] {\n const b = a + 1;\n const { total, low, high, shut, full } = pairRange(sizes, a, bounds);\n let size: number;\n if (shut && target < bounds[a].min / 2) size = 0;\n else if (full && total - target < bounds[b].min / 2) size = total;\n else if (low > high + EPS) size = sizes[a];\n else size = clamp(target, low, high);\n const next = [...sizes];\n next[a] = size;\n next[b] = total - size;\n return next;\n}\n\n/**\n * The aria value range of a handle's primary pane: zero at the bottom when\n * it can shut, everything the pair holds at the top when the other pane can.\n */\nexport function primaryRange(\n sizes: number[],\n a: number,\n primary: number,\n bounds: PaneBounds[]\n) {\n const { total, low, high, shut, full } = pairRange(sizes, a, bounds);\n const minA = shut ? 0 : low;\n const maxA = full ? total : high;\n return primary === a\n ? { now: sizes[a], min: minA, max: maxA }\n : { now: sizes[a + 1], min: total - maxA, max: total - minA };\n}\n"],"names":[],"mappings":"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"}
|