{"mappings":"AAAA;;;;;;;;;;CAUC,GAMM,SAAS,0CAAS,KAAyB;IAChD,OAAO,SAAS,QAAS,CAAA,CAAC,MAAM,UAAoB,AAAC,OAAO,OAAQ,KAAK,CAAC,oBAAoB,IAAG;AACnG;AAEO,SAAS,0CAAoB,KAAyB;IAC3D,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B,OAAO;IAET,IAAI,QAAQ,MAAM,KAAK,CAAC;IACxB,6DAA6D;IAC7D,IAAI,CAAC,OAAO;QACV,IAAI,QAAQ,GAAG,CAAC,QAAQ,KAAK,cAC3B,QAAQ,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,6GAA6G,CAAC,EACzI;QAEJ,OAAO;IACT;IACA,OAAO,WAAW,KAAK,CAAC,EAAE;AAC5B;AAEO,SAAS,0CAAiB,KAAsB,EAAE,UAAkB;IACzE,IAAI,OAAO,UAAU,UAAU;QAC7B,IAAI,QAAQ,MAAM,KAAK,CAAC;QACxB,IAAI,CAAC,OACH,MAAM,IAAI,MAAM;QAElB,OAAO,aAAc,CAAA,WAAW,KAAK,CAAC,EAAE,IAAI,GAAE;IAChD;IACA,OAAO;AACT;AAGO,SAAS,0CAAY,QAA4C,EAAE,UAAkB;IAC1F,OAAO,YAAY,OACf,0CAAiB,UAAU,cAC3B,OAAO,gBAAgB;AAC7B;AAGO,SAAS,0CAAY,QAAyB,EAAE,UAAkB;IACvE,OAAO,YAAY,OACf,0CAAiB,UAAU,cAC3B;AACN;AA+CO,SAAS,0CAAqB,cAAsB,EAAE,OAAkB,EAAE,cAAoC,EAAE,eAAkE,EAAE,kBAAqE;IAC9P,IAAI,oBAAoB;IACxB,IAAI,YAAwB,QAAQ,GAAG,CAAC,CAAC,QAAQ;QAC/C,IAAI,QAAqB,eAAe,GAAG,CAAC,OAAO,GAAG,KAAK,OAAO,eAAe,GAAG,CAAC,OAAO,GAAG,KAAK,QAAQ,OAAO,KAAK,IAAI,OAAO,YAAY,IAAI,kBAAkB,UAAU;QAC/K,IAAI,SAAS;QACb,IAAI,WAAW;QACf,IAAI,OAAO;QACX,IAAI,iBAAiB;QACrB,IAAI,0CAAS,QAAQ;YACnB,WAAW,0CAAiB,OAAO;YACnC,SAAS;QACX,OAAO;YACL,OAAO,0CAAoB;YAC3B,IAAI,QAAQ,GACV,SAAS;QAEb;QAEA,IAAI,MAAM,0CAAY,OAAO,QAAQ,IAAI,qBAAqB,UAAU,GAAG;QAC3E,IAAI,MAAM,0CAAY,OAAO,QAAQ,EAAE;QACvC,IAAI,uBAAuB,KAAK,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,UAAU;QAE5D,QAAQ;QACR,mFAAmF;QACnF,QAAQ;QACR,IAAI,QACF,iBAAiB;aACZ,IAAI,WAAW,sBAAsB;YAC1C,SAAS;YACT,iBAAiB;QACnB;QAEA,QAAQ;QACR,IAAI,CAAC,QACH,oBAAoB;QAEtB,OAAO;oBACL;sBACA;kCACA;iBACA;iBACA;kBACA;4BACA;YACA,WAAW;QACb;IACF;IAEA,QAAQ;IACR,UAAU;IACV,MAAO,kBAAmB;QACxB,UAAU;QACV;;;;;;KAMC,GACD,IAAI,YAAY;QAChB,IAAI,cAAc;QAClB,UAAU,OAAO,CAAC,CAAA;YAChB,IAAI,KAAK,MAAM,EACb,aAAa,KAAK,cAAc;iBAC3B;gBACL,aAAa,KAAK,QAAQ;gBAC1B,eAAe,KAAK,IAAI;YAC1B;QACF;QAEA,IAAI,qBAAqB,iBAAiB;QAC1C,+FAA+F;QAC/F,0CAA0C;QAC1C,UAAU;QACV;;;;;;;;;KASC,GACD,IAAI,qBAAqB,GACvB,UAAU,OAAO,CAAC,CAAC;YACjB,IAAI,CAAC,KAAK,MAAM,EAAE;gBAChB,IAAI,QAAQ,KAAK,IAAI,GAAG;gBACxB,KAAK,cAAc,GAAG,KAAK,QAAQ,GAAI,QAAQ;YACjD;QACF;QAGF,UAAU;QACV;;;;;;;KAOC,GACD,IAAI,iBAAiB;QACrB,UAAU,OAAO,CAAC,CAAA;YAChB,KAAK,SAAS,GAAG;YACjB,IAAI,CAAC,KAAK,MAAM,EAAE;gBAChB,IAAI,OAAC,GAAG,OAAE,GAAG,kBAAE,cAAc,EAAC,GAAG;gBACjC,KAAK,cAAc,GAAG,KAAK,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,gBAAgB;gBAE7D,KAAK,SAAS,GAAG,KAAK,cAAc,GAAG;gBACvC,kBAAkB,KAAK,SAAS;YAClC;QACF;QAEA,UAAU;QACV;;;;;;;;;;;;KAYC,GACD,oBAAoB;QACpB,UAAU,OAAO,CAAC,CAAA;YAChB,IAAI,mBAAmB,KAAK,KAAK,IAAI,CAAC,oBAAoB,KAAK,IAAI,CAAC,KAAK,SAAS,GAChF,KAAK,MAAM,GAAG;iBACT,IAAI,CAAC,KAAK,MAAM,EACrB,oBAAoB;QAExB;IACF;IAEA,OAAO,sCAAgB;AACzB;AAEA,SAAS,sCAAgB,SAAqB;IAC5C;;;EAGA,GAEA,IAAI,UAAU;IACd,IAAI,WAAW;IACf,IAAI,eAAyB,EAAE;IAC/B,UAAU,OAAO,CAAC,SAAU,IAAI;QAC9B,IAAI,QAAQ,KAAK,cAAc;QAC/B,IAAI,UAAU,KAAK,KAAK,CAAC,QAAQ,WAAW;QAC5C,WAAW;QACX,YAAY;QACZ,aAAa,IAAI,CAAC;IACpB;IAEA,OAAO;AACT","sources":["packages/react-stately/src/table/TableUtils.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {ColumnSize} from './Column';\nimport {Key} from '@react-types/shared';\n\n// numbers and percents are considered static. *fr units or a lack of units are considered dynamic.\nexport function isStatic(width?: ColumnSize | null): boolean {\n  return width != null && (!isNaN(width as number) || (String(width)).match(/^(\\d+)(?=%$)/) !== null);\n}\n\nexport function parseFractionalUnit(width?: ColumnSize | null): number {\n  if (!width || typeof width === 'number') {\n    return 1;\n  }\n  let match = width.match(/^(.+)(?=fr$)/);\n  // if width is the incorrect format, just default it to a 1fr\n  if (!match) {\n    if (process.env.NODE_ENV !== 'production') {\n      console.warn(`width: ${width} is not a supported format, width should be a number (ex. 150), percentage (ex. '50%') or fr unit (ex. '2fr')`,\n        'defaulting to \\'1fr\\'');\n    }\n    return 1;\n  }\n  return parseFloat(match[0]);\n}\n\nexport function parseStaticWidth(width: number | string, tableWidth: number): number {\n  if (typeof width === 'string') {\n    let match = width.match(/^(\\d+)(?=%$)/);\n    if (!match) {\n      throw new Error('Only percentages or numbers are supported for static column widths');\n    }\n    return tableWidth * (parseFloat(match[0]) / 100);\n  }\n  return width;\n}\n\n\nexport function getMaxWidth(maxWidth: number | string | null | undefined, tableWidth: number): number {\n  return maxWidth != null\n    ? parseStaticWidth(maxWidth, tableWidth)\n    : Number.MAX_SAFE_INTEGER;\n}\n\n// cannot support FR units, we'd need to know everything else in the table to do that\nexport function getMinWidth(minWidth: number | string, tableWidth: number): number {\n  return minWidth != null\n    ? parseStaticWidth(minWidth, tableWidth)\n    : 0;\n}\n\n\nexport interface IColumn {\n  minWidth?: number | string,\n  maxWidth?: number | string,\n  width?: number | string,\n  defaultWidth?: number | string,\n  key: Key\n}\n\ninterface FlexItem {\n  frozen: boolean,\n  baseSize: number,\n  hypotheticalMainSize: number,\n  min: number,\n  max: number,\n  flex: number,\n  targetMainSize: number,\n  violation: number\n}\n\n/**\n * Implements the flex algorithm described in https://www.w3.org/TR/css-flexbox-1/#layout-algorithm\n * It makes a few constraint/assumptions:\n * 1. All basis values are 0 unless it is a static width, then the basis is the static width\n * 2. All flex grow and shrink values are equal to the FR specified on the column, grow and shrink for the same column are equal\n * 3. We only have one row\n * An example of the setup can be seen here https://jsfiddle.net/snowystinger/wv0ymjaf/61/ where I let the browser figure out the\n * flex of the columns.\n * Note: We differ in one key aspect, all of our column widths must be whole numbers, so we avoid browser\n * sub pixel rounding errors. To do this, we use a cascading rounding algorithm to ensure that the sum of the widths is maintained\n * while distributing the rounding remainder across the columns.\n *\n * As noted in the chrome source code, this algorithm is very accurate, but has the potential to be quadratic.\n * They have deemed this to be acceptable because the number of elements is usually small and the flex factors\n * are usually not high variance. I believe we can make the same assumptions. Particularly once resizing is\n * started, it will convert all columns to the left to static widths, so it will cut down on the number of FR columns.\n *\n * There are likely faster ways to do this, I've chosen to stick to the spec as closely as possible for readability, accuracy, and for the\n * note that this behaving quadratically is unlikely to be a problem.\n * @param availableWidth - The visible width of the table.\n * @param columns - The table defined columns.\n * @param changedColumns - Any columns we want to override, for example, during resizing.\n * @param getDefaultWidth - A function that returns the default width of a column by its index.\n * @param getDefaultMinWidth - A function that returns the default min width of a column by its index.\n */\nexport function calculateColumnSizes(availableWidth: number, columns: IColumn[], changedColumns: Map<Key, ColumnSize>, getDefaultWidth?: (index: number) => ColumnSize | null | undefined, getDefaultMinWidth?: (index: number) => ColumnSize | null | undefined): number[] {\n  let hasNonFrozenItems = false;\n  let flexItems: FlexItem[] = columns.map((column, index) => {\n    let width: ColumnSize = (changedColumns.get(column.key) != null ? changedColumns.get(column.key) ?? '1fr' : column.width ?? column.defaultWidth ?? getDefaultWidth?.(index) ?? '1fr') as ColumnSize;\n    let frozen = false;\n    let baseSize = 0;\n    let flex = 0;\n    let targetMainSize = 0;\n    if (isStatic(width)) {\n      baseSize = parseStaticWidth(width, availableWidth);\n      frozen = true;\n    } else {\n      flex = parseFractionalUnit(width);\n      if (flex <= 0) {\n        frozen = true;\n      }\n    }\n\n    let min = getMinWidth(column.minWidth ?? getDefaultMinWidth?.(index) ?? 0, availableWidth);\n    let max = getMaxWidth(column.maxWidth, availableWidth);\n    let hypotheticalMainSize = Math.max(min, Math.min(baseSize, max));\n\n    // 9.7.1\n    // We don't make use of flex basis, it's always 0, so we are always in 'grow' mode.\n    // 9.7.2\n    if (frozen) {\n      targetMainSize = hypotheticalMainSize;\n    } else if (baseSize > hypotheticalMainSize) {\n      frozen = true;\n      targetMainSize = hypotheticalMainSize;\n    }\n\n    // 9.7.3\n    if (!frozen) {\n      hasNonFrozenItems = true;\n    }\n    return {\n      frozen,\n      baseSize,\n      hypotheticalMainSize,\n      min,\n      max,\n      flex,\n      targetMainSize,\n      violation: 0\n    };\n  });\n\n  // 9.7.4\n  // 9.7.4.a\n  while (hasNonFrozenItems) {\n    // 9.7.4.b\n    /**\n     * Calculate the remaining free space as for initial free space,\n     * above (9.7.3). If the sum of the unfrozen flex items’ flex factors is\n     * less than one, multiply the initial free space by this sum (of flex factors).\n     * If the magnitude of this value is less than the magnitude of\n     * the remaining free space, use this as the remaining free space.\n     */\n    let usedWidth = 0;\n    let flexFactors = 0;\n    flexItems.forEach(item => {\n      if (item.frozen) {\n        usedWidth += item.targetMainSize;\n      } else {\n        usedWidth += item.baseSize;\n        flexFactors += item.flex;\n      }\n    });\n\n    let remainingFreeSpace = availableWidth - usedWidth;\n    // we only support integer FR's, and because of hasNonFrozenItems, we know that flexFactors > 0\n    // so no need to check for flexFactors < 1\n    // 9.7.4.c\n    /**\n     * If the remaining free space is zero\n     * - Do nothing.\n     * Else // remember, we're always in grow mode\n     * - Find the ratio of the item’s flex grow factor to the\n     * sum of the flex grow factors of all unfrozen items on\n     * the line. Set the item’s target main size to its flex\n     * base size plus a fraction of the remaining free space\n     * proportional to the ratio.\n     */\n    if (remainingFreeSpace > 0) {\n      flexItems.forEach((item) => {\n        if (!item.frozen) {\n          let ratio = item.flex / flexFactors;\n          item.targetMainSize = item.baseSize + (ratio * remainingFreeSpace);\n        }\n      });\n    }\n\n    // 9.7.4.d\n    /**\n     * Fix min/max violations. Clamp each non-frozen item’s\n     * target main size by its used min and max main sizes\n     * and floor its content-box size at zero. If the item’s\n     * target main size was made smaller by this, it’s a max\n     * violation. If the item’s target main size was made\n     * larger by this, it’s a min violation.\n     */\n    let totalViolation = 0;\n    flexItems.forEach(item => {\n      item.violation = 0;\n      if (!item.frozen) {\n        let {min, max, targetMainSize} = item;\n        item.targetMainSize = Math.max(min, Math.min(targetMainSize, max));\n\n        item.violation = item.targetMainSize - targetMainSize;\n        totalViolation += item.violation;\n      }\n    });\n\n    // 9.7.4.e\n    /**\n     * Freeze over-flexed items. The total violation is the\n     * sum of the adjustments from the previous step\n     * ∑(clamped size - unclamped size). If the total violation is:\n     * Zero\n     * - Freeze all items.\n     *\n     * Positive\n     * - Freeze all the items with min violations.\n     *\n     * Negative\n     * - Freeze all the items with max violations.\n     */\n    hasNonFrozenItems = false;\n    flexItems.forEach(item => {\n      if (totalViolation === 0 || Math.sign(totalViolation) === Math.sign(item.violation)) {\n        item.frozen = true;\n      } else if (!item.frozen) {\n        hasNonFrozenItems = true;\n      }\n    });\n  }\n\n  return cascadeRounding(flexItems);\n}\n\nfunction cascadeRounding(flexItems: FlexItem[]): number[] {\n  /*\n  Given an array of floats that sum to an integer, this rounds the floats\n  and returns an array of integers with the same sum.\n  */\n\n  let fpTotal = 0;\n  let intTotal = 0;\n  let roundedArray: number[] = [];\n  flexItems.forEach(function (item) {\n    let float = item.targetMainSize;\n    let integer = Math.round(float + fpTotal) - intTotal;\n    fpTotal += float;\n    intTotal += integer;\n    roundedArray.push(integer);\n  });\n\n  return roundedArray;\n}\n"],"names":[],"version":3,"file":"TableUtils.mjs.map"}