diff --git a/docs/11-date-formatting.mdx b/docs/11-date-formatting.mdx
index 46b746459..f0cca2cf1 100644
--- a/docs/11-date-formatting.mdx
+++ b/docs/11-date-formatting.mdx
@@ -1,9 +1,9 @@
import { Meta, Story } from '../.storybook/components';
import * as Stories from './date-formatting.stories';
-
+
-# Date formatter
+# DateFormatter
The `DateFormatter` is a unified system for formatting dates and times.
It ensures consistent output across the application based on shared product rules.
diff --git a/docs/date-formatting.stories.tsx b/docs/date-formatting.stories.tsx
index 2dc008bcc..58b85e3e5 100644
--- a/docs/date-formatting.stories.tsx
+++ b/docs/date-formatting.stories.tsx
@@ -11,7 +11,7 @@ import {
import type { StoryObj } from '@storybook/react';
const meta = {
- title: 'Date formatter',
+ title: 'Utilities/DateFormatter',
parameters: {
layout: 'padded',
},
@@ -41,7 +41,7 @@ function FormatsTable({
return (
-
+
Name
Value
@@ -71,7 +71,7 @@ function DurationShortestTable({
return (
-
+
Name
Seconds
diff --git a/packages/core/src/hooks/index.ts b/packages/core/src/hooks/index.ts
index 139086702..ef479c17e 100644
--- a/packages/core/src/hooks/index.ts
+++ b/packages/core/src/hooks/index.ts
@@ -22,3 +22,4 @@ export * from './useScrollPosition';
export * from './useCopyToClipboard';
export * from './useTimer';
export * from './useKeyedRefs';
+export * from './useFileSizeFormatter';
diff --git a/packages/core/src/hooks/useFileSizeFormatter/index.ts b/packages/core/src/hooks/useFileSizeFormatter/index.ts
new file mode 100644
index 000000000..8aa5306ff
--- /dev/null
+++ b/packages/core/src/hooks/useFileSizeFormatter/index.ts
@@ -0,0 +1 @@
+export * from './useFileSizeFormatter';
diff --git a/packages/core/src/hooks/useFileSizeFormatter/useFileSizeFormatter.test.tsx b/packages/core/src/hooks/useFileSizeFormatter/useFileSizeFormatter.test.tsx
new file mode 100644
index 000000000..ea9273b10
--- /dev/null
+++ b/packages/core/src/hooks/useFileSizeFormatter/useFileSizeFormatter.test.tsx
@@ -0,0 +1,48 @@
+import type { ReactNode } from 'react';
+
+import { I18nProvider } from '@react-aria/i18n';
+import { renderHook } from '@testing-library/react';
+import { describe, expect, it } from 'vitest';
+
+import type { FileSizeFormatterConfig } from '../../utils/FileSizeFormatter';
+
+import { useFileSizeFormatter } from './useFileSizeFormatter';
+
+const withLocale = (locale: string) =>
+ function Wrapper({ children }: { children: ReactNode }) {
+ return {children};
+ };
+
+describe('useFileSizeFormatter', () => {
+ it('formats using the current locale', () => {
+ const { result } = renderHook(() => useFileSizeFormatter(), {
+ wrapper: withLocale('ru-RU'),
+ });
+
+ expect(result.current.format(1500)).toBe('1,5 КБ');
+ });
+
+ it('applies the provided config', () => {
+ const { result } = renderHook(
+ () => useFileSizeFormatter({ defaultUnitSystem: 'IEC' }),
+ { wrapper: withLocale('en-US') }
+ );
+
+ expect(result.current.format(1024)).toBe('1 KiB');
+ });
+
+ it('reuses the formatter across renders with an equal config', () => {
+ const config: FileSizeFormatterConfig = { defaultPrecision: 1 };
+
+ const { result, rerender } = renderHook(
+ () => useFileSizeFormatter(config),
+ { wrapper: withLocale('en-US') }
+ );
+
+ const first = result.current;
+
+ rerender();
+
+ expect(result.current).toBe(first);
+ });
+});
diff --git a/packages/core/src/hooks/useFileSizeFormatter/useFileSizeFormatter.ts b/packages/core/src/hooks/useFileSizeFormatter/useFileSizeFormatter.ts
new file mode 100644
index 000000000..8bf476009
--- /dev/null
+++ b/packages/core/src/hooks/useFileSizeFormatter/useFileSizeFormatter.ts
@@ -0,0 +1,28 @@
+import { useMemo } from 'react';
+
+import { useLocale } from '@react-aria/i18n';
+
+import {
+ FileSizeFormatter,
+ type FileSizeFormatterConfig,
+} from '../../utils/FileSizeFormatter';
+
+/**
+ * Returns a memoized {@link FileSizeFormatter} bound to the current locale.
+ * The formatter is recreated only when the locale or `config` changes.
+ * @example
+ * const formatter = useFileSizeFormatter();
+ * formatter.format(1500); // "1.5 KB"
+ */
+export function useFileSizeFormatter(
+ config?: FileSizeFormatterConfig
+): FileSizeFormatter {
+ const { locale } = useLocale();
+
+ // `config` is a plain data object, so a stable serialization keeps the
+ // formatter memoized across renders that pass an equal inline literal.
+ return useMemo(
+ () => new FileSizeFormatter(locale, config),
+ [locale, JSON.stringify(config)]
+ );
+}
diff --git a/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.mdx b/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.mdx
new file mode 100644
index 000000000..056ce303e
--- /dev/null
+++ b/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.mdx
@@ -0,0 +1,92 @@
+import { Meta, Story, Status } from '../../../../../.storybook/components';
+
+import * as Stories from './FileSizeFormatter.stories';
+
+
+
+# FileSizeFormatter
+
+
+
+Formats byte values using SI and IEC measurement systems.
+
+## Import
+
+```tsx
+import { FileSizeFormatter } from '@koobiq/react-core';
+```
+
+## Usage
+
+Create one formatter for a locale and reuse it.
+
+```tsx
+const formatter = new FileSizeFormatter('en-US');
+
+formatter.format(1500);
+// 1.5 KB
+```
+
+SI is used by default: `1 KB = 1000 bytes`. Use IEC for binary units, where
+`1 KiB = 1024 bytes`.
+
+```tsx
+const formatter = new FileSizeFormatter('en-US', {
+ defaultUnitSystem: 'IEC',
+});
+
+formatter.format(1536);
+// 1.5 KiB
+```
+
+
+
+## Hook
+
+Use `useFileSizeFormatter` inside components. It reads the current locale from
+context and memoizes the formatter, so it's only recreated when the locale or
+`config` changes.
+
+```tsx
+import { useFileSizeFormatter } from '@koobiq/react-core';
+
+function FileSize({ bytes }: { bytes: number }) {
+ const formatter = useFileSizeFormatter();
+
+ return {formatter.format(bytes)};
+}
+```
+
+Pass a `config` to switch measurement systems, change precision, or override
+unit labels:
+
+```tsx
+const formatter = useFileSizeFormatter({
+ defaultUnitSystem: 'IEC',
+ defaultPrecision: 1,
+});
+```
+
+## Precision
+
+The default maximum precision is two fraction digits. Override it for the
+formatter or an individual value.
+
+```tsx
+const formatter = new FileSizeFormatter('en-US', {
+ defaultPrecision: 1,
+});
+
+formatter.format(1550);
+// 1.6 KB
+
+formatter.format(1550, { precision: 2 });
+// 1.55 KB
+```
+
+## Localization
+
+The locale controls number formatting and unit abbreviations. A non-breaking
+space is always used between the value and unit.
+
+
diff --git a/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.stories.tsx b/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.stories.tsx
new file mode 100644
index 000000000..663b8eddf
--- /dev/null
+++ b/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.stories.tsx
@@ -0,0 +1,88 @@
+import { Table, TableContainer } from '@koobiq/react-components';
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { FileSizeFormatter } from './FileSizeFormatter';
+
+const meta = {
+ title: 'Utilities/FileSizeFormatter',
+ parameters: { layout: 'padded' },
+} satisfies Meta;
+
+export default meta;
+
+type Story = StoryObj;
+
+const values = [512, 1000, 1024, 1_000_000, 1024 ** 2];
+
+type FormatRow = { id: number } & Record;
+
+const FormatsTable = ({
+ formatters,
+}: {
+ formatters: Array<{ name: string; formatter: FileSizeFormatter }>;
+}) => {
+ const columns = [
+ { id: 'bytes', name: 'Bytes' },
+ ...formatters.map(({ name }, index) => ({
+ id: `format-${index}`,
+ name,
+ })),
+ ];
+
+ const items: FormatRow[] = values.map((value) => ({
+ id: value,
+ bytes: value,
+ ...Object.fromEntries(
+ formatters.map(({ formatter }, index) => [
+ `format-${index}`,
+ formatter.format(value),
+ ])
+ ),
+ }));
+
+ return (
+
+
+
+ {(column) => {column.name}}
+
+
+ {(item) => (
+
+ {(columnKey) => (
+ {item[String(columnKey)]}
+ )}
+
+ )}
+
+
+
+ );
+};
+
+export const Base: Story = {
+ render: () => (
+
+ ),
+};
+
+export const Localization: Story = {
+ render: () => (
+
+ ),
+};
diff --git a/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.test.ts b/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.test.ts
new file mode 100644
index 000000000..ff8934030
--- /dev/null
+++ b/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.test.ts
@@ -0,0 +1,127 @@
+import { describe, expect, it } from 'vitest';
+
+import { FileSizeFormatter } from './FileSizeFormatter';
+
+describe('FileSizeFormatter', () => {
+ it('formats values using SI units by default', () => {
+ const formatter = new FileSizeFormatter('en-US');
+
+ expect(formatter.format(999)).toBe('999\u00a0B');
+ expect(formatter.format(1000)).toBe('1\u00a0KB');
+ expect(formatter.format(1_000_000)).toBe('1\u00a0MB');
+ });
+
+ it('formats values using IEC units', () => {
+ const formatter = new FileSizeFormatter('en-US', {
+ defaultUnitSystem: 'IEC',
+ });
+
+ expect(formatter.format(1023)).toBe('1,023\u00a0B');
+ expect(formatter.format(1024)).toBe('1\u00a0KiB');
+ expect(formatter.format(1024 ** 2)).toBe('1\u00a0MiB');
+ });
+
+ it('caps formatting at the largest unit', () => {
+ const formatter = new FileSizeFormatter('en-US');
+
+ expect(formatter.format(1000 ** 6)).toBe('1,000,000\u00a0TB');
+ });
+
+ it('uses the configured precision and allows overriding it', () => {
+ const formatter = new FileSizeFormatter('en-US', {
+ defaultPrecision: 1,
+ });
+
+ expect(formatter.format(1550)).toBe('1.6\u00a0KB');
+ expect(formatter.format(1550, { precision: 2 })).toBe('1.55\u00a0KB');
+ });
+
+ it('allows overriding the measurement system per call', () => {
+ const formatter = new FileSizeFormatter('en-US');
+
+ expect(formatter.format(1024, { unitSystem: 'IEC' })).toBe('1\u00a0KiB');
+ });
+
+ it('localizes numbers and unit abbreviations', () => {
+ const formatter = new FileSizeFormatter('ru-RU');
+
+ expect(formatter.format(1500)).toBe('1,5\u00a0КБ');
+
+ expect(formatter.format(1536, { unitSystem: 'IEC' })).toBe('1,5\u00a0КиБ');
+ });
+
+ it('allows overriding a localized unit system', () => {
+ const formatter = new FileSizeFormatter('en-US', {
+ unitSystems: {
+ SI: { abbreviations: ['byte', 'kB', 'MB', 'GB', 'TB'] },
+ },
+ });
+
+ expect(formatter.format(1000)).toBe('1\u00a0kB');
+ });
+
+ it('formats zero and negative finite values', () => {
+ const formatter = new FileSizeFormatter('en-US');
+
+ expect(formatter.format(0)).toBe('0\u00a0B');
+ expect(formatter.format(-100)).toBe('-100\u00a0B');
+ });
+
+ it('scales negative values by magnitude', () => {
+ const formatter = new FileSizeFormatter('en-US');
+
+ expect(formatter.format(-1_500_000)).toBe('-1.5\u00a0MB');
+ expect(formatter.format(-1024, { unitSystem: 'IEC' })).toBe('-1\u00a0KiB');
+ });
+
+ it('moves up a unit when rounding reaches the next threshold', () => {
+ const formatter = new FileSizeFormatter('en-US');
+
+ expect(formatter.format(999_999)).toBe('1\u00a0MB');
+ expect(formatter.format(999_999_999)).toBe('1\u00a0GB');
+ // Below the rounding threshold the smaller unit is kept.
+ expect(formatter.format(999_990)).toBe('999.99\u00a0KB');
+ });
+
+ it('clamps out-of-range precision instead of throwing', () => {
+ const formatter = new FileSizeFormatter('en-US');
+
+ expect(formatter.format(1550, { precision: -1 })).toBe('2\u00a0KB');
+ expect(() => formatter.format(1550, { precision: 101 })).not.toThrow();
+ });
+
+ it('falls back to the configured precision when a per-call override is non-finite', () => {
+ const formatter = new FileSizeFormatter('en-US', {
+ defaultPrecision: 1,
+ });
+
+ expect(formatter.format(1550, { precision: Number.NaN })).toBe(
+ '1.6\u00a0KB'
+ );
+
+ expect(
+ formatter.format(1550, { precision: Number.POSITIVE_INFINITY })
+ ).toBe('1.6\u00a0KB');
+ });
+
+ it('does not treat "rue" as Russian', () => {
+ const formatter = new FileSizeFormatter('rue');
+
+ expect(formatter.format(1000)).toContain('KB');
+ });
+
+ it('throws for non-finite values', () => {
+ const formatter = new FileSizeFormatter('en-US');
+ const expectedError = 'Argument "value" must be a finite number!';
+
+ expect(() => formatter.format(Number.NaN)).toThrow(expectedError);
+
+ expect(() => formatter.format(Number.POSITIVE_INFINITY)).toThrow(
+ expectedError
+ );
+
+ expect(() => formatter.format(null as unknown as number)).toThrow(
+ expectedError
+ );
+ });
+});
diff --git a/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.ts b/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.ts
new file mode 100644
index 000000000..f8e3e1626
--- /dev/null
+++ b/packages/core/src/utils/FileSizeFormatter/FileSizeFormatter.ts
@@ -0,0 +1,238 @@
+import { once } from '@koobiq/logger';
+
+/** Measurement systems supported by `FileSizeFormatter`. */
+export const fileSizeMeasurementSystem = ['SI', 'IEC'] as const;
+
+/** A measurement system supported by `FileSizeFormatter`. */
+export type FileSizeMeasurementSystem =
+ (typeof fileSizeMeasurementSystem)[number];
+
+/** Unit abbreviations ordered from bytes through terabytes. */
+export type FileSizeUnitAbbreviations = readonly [
+ string,
+ string,
+ string,
+ string,
+ string,
+];
+
+/** Scaling and unit labels for a file-size measurement system. */
+export type FileSizeUnitSystem = {
+ abbreviations: FileSizeUnitAbbreviations;
+ base: number;
+ power: number;
+};
+
+/** Default settings and unit-system overrides for `FileSizeFormatter`. */
+export type FileSizeFormatterConfig = {
+ /**
+ * Default measurement system.
+ * @default 'SI'
+ */
+ defaultUnitSystem?: FileSizeMeasurementSystem;
+ /**
+ * Default maximum number of fraction digits.
+ * @default 2
+ */
+ defaultPrecision?: number;
+ /** Overrides the built-in localized unit systems. */
+ unitSystems?: Partial<
+ Record>
+ >;
+};
+
+/** Overrides for formatting an individual byte value. */
+export type FileSizeFormatOptions = {
+ /** Overrides the configured maximum number of fraction digits. */
+ precision?: number;
+ /** Overrides the configured measurement system. */
+ unitSystem?: FileSizeMeasurementSystem;
+};
+
+const INVALID_VALUE_ERROR = 'Argument "value" must be a finite number!';
+const NON_BREAKING_SPACE = '\u00a0';
+
+const DEFAULT_PRECISION = 2;
+const MIN_PRECISION = 0;
+const MAX_PRECISION = 100;
+
+export const FILE_SIZE_FORMATTER_ERROR_PRECISION_RANGE = `FileSizeFormatter: "precision" must be an integer between ${MIN_PRECISION} and ${MAX_PRECISION}.`;
+
+// Base and power are physics, not localization — they stay constant across
+// languages, so keep them separate from the per-locale abbreviations.
+const unitSystemScales: Record<
+ FileSizeMeasurementSystem,
+ Pick
+> = {
+ SI: { base: 10, power: 3 },
+ IEC: { base: 2, power: 10 },
+};
+
+const DEFAULT_LANGUAGE = 'en';
+
+const localizedAbbreviations: Record<
+ string,
+ Record
+> = {
+ en: {
+ SI: ['B', 'KB', 'MB', 'GB', 'TB'],
+ IEC: ['B', 'KiB', 'MiB', 'GiB', 'TiB'],
+ },
+ ru: {
+ SI: ['Б', 'КБ', 'МБ', 'ГБ', 'ТБ'],
+ IEC: ['Б', 'КиБ', 'МиБ', 'ГиБ', 'ТиБ'],
+ },
+};
+
+const getLocalizedUnitSystems = (
+ locale: string
+): Record => {
+ const language = new Intl.Locale(locale).language;
+
+ const abbreviations =
+ localizedAbbreviations[language] ??
+ localizedAbbreviations[DEFAULT_LANGUAGE];
+
+ return {
+ SI: { ...unitSystemScales.SI, abbreviations: abbreviations.SI },
+ IEC: { ...unitSystemScales.IEC, abbreviations: abbreviations.IEC },
+ };
+};
+
+const mergeUnitSystem = (
+ defaults: FileSizeUnitSystem,
+ overrides?: Partial
+): FileSizeUnitSystem => ({
+ abbreviations: overrides?.abbreviations ?? defaults.abbreviations,
+ base: overrides?.base ?? defaults.base,
+ power: overrides?.power ?? defaults.power,
+});
+
+const isPrecisionInRange = (precision: number): boolean =>
+ Number.isInteger(precision) &&
+ precision >= MIN_PRECISION &&
+ precision <= MAX_PRECISION;
+
+const clampPrecision = (precision: number, fallback: number): number => {
+ if (!Number.isFinite(precision)) return fallback;
+
+ return Math.min(
+ Math.max(Math.trunc(precision), MIN_PRECISION),
+ MAX_PRECISION
+ );
+};
+
+const getHumanizedSize = (
+ value: number,
+ system: FileSizeUnitSystem,
+ precision: number
+): { value: number; unit: string } => {
+ const orderOfMagnitude = system.base ** system.power;
+ const lastUnitIndex = system.abbreviations.length - 1;
+ const magnitude = Math.abs(value);
+
+ let unitIndex = 0;
+ let result = magnitude;
+
+ while (unitIndex < lastUnitIndex && result >= orderOfMagnitude) {
+ unitIndex += 1;
+ result = magnitude / orderOfMagnitude ** unitIndex;
+ }
+
+ // Rounding can land back on the threshold the loop just cleared, so 999_999 B
+ // would read as "1000 KB" rather than "1 MB".
+ if (
+ unitIndex < lastUnitIndex &&
+ Number(result.toFixed(precision)) >= orderOfMagnitude
+ ) {
+ unitIndex += 1;
+ result = magnitude / orderOfMagnitude ** unitIndex;
+ }
+
+ return {
+ value: value < 0 ? -result : result,
+ unit: system.abbreviations[unitIndex],
+ };
+};
+
+/** Formats byte values using Koobiq SI or IEC file-size conventions. */
+export class FileSizeFormatter {
+ private readonly locale: string;
+ private readonly defaultPrecision: number;
+ private readonly defaultUnitSystem: FileSizeMeasurementSystem;
+ private readonly unitSystems: Record<
+ FileSizeMeasurementSystem,
+ FileSizeUnitSystem
+ >;
+ private readonly numberFormatters = new Map();
+
+ constructor(locale?: string, config: FileSizeFormatterConfig = {}) {
+ this.locale = new Intl.NumberFormat(locale).resolvedOptions().locale;
+
+ const localizedUnitSystems = getLocalizedUnitSystems(this.locale);
+
+ this.defaultPrecision = this.resolvePrecision(
+ config.defaultPrecision,
+ DEFAULT_PRECISION
+ );
+
+ this.defaultUnitSystem = config.defaultUnitSystem ?? 'SI';
+
+ this.unitSystems = {
+ SI: mergeUnitSystem(localizedUnitSystems.SI, config.unitSystems?.SI),
+ IEC: mergeUnitSystem(localizedUnitSystems.IEC, config.unitSystems?.IEC),
+ };
+ }
+
+ /** Formats a byte value using the configured locale and measurement system. */
+ format(value: number, options: FileSizeFormatOptions = {}): string {
+ if (!Number.isFinite(value)) {
+ throw new Error(INVALID_VALUE_ERROR);
+ }
+
+ const precision = this.resolvePrecision(
+ options.precision,
+ this.defaultPrecision
+ );
+
+ const unitSystem = options.unitSystem ?? this.defaultUnitSystem;
+
+ const formattedSize = getHumanizedSize(
+ value,
+ this.unitSystems[unitSystem],
+ precision
+ );
+
+ return `${this.getNumberFormatter(precision).format(formattedSize.value)}${NON_BREAKING_SPACE}${formattedSize.unit}`;
+ }
+
+ private resolvePrecision(
+ precision: number | undefined,
+ fallback: number
+ ): number {
+ if (precision === undefined) return fallback;
+
+ if (
+ process.env.NODE_ENV !== 'production' &&
+ !isPrecisionInRange(precision)
+ ) {
+ once.warn(FILE_SIZE_FORMATTER_ERROR_PRECISION_RANGE);
+ }
+
+ return clampPrecision(precision, fallback);
+ }
+
+ private getNumberFormatter(precision: number): Intl.NumberFormat {
+ let formatter = this.numberFormatters.get(precision);
+
+ if (!formatter) {
+ formatter = new Intl.NumberFormat(this.locale, {
+ maximumFractionDigits: precision,
+ });
+
+ this.numberFormatters.set(precision, formatter);
+ }
+
+ return formatter;
+ }
+}
diff --git a/packages/core/src/utils/FileSizeFormatter/index.ts b/packages/core/src/utils/FileSizeFormatter/index.ts
new file mode 100644
index 000000000..35921d419
--- /dev/null
+++ b/packages/core/src/utils/FileSizeFormatter/index.ts
@@ -0,0 +1 @@
+export * from './FileSizeFormatter';
diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts
index c6c0701b9..c300a2027 100644
--- a/packages/core/src/utils/index.ts
+++ b/packages/core/src/utils/index.ts
@@ -3,3 +3,4 @@ export * from './typeGuards/index.js';
export * from './setRef.js';
export * from './isBrowser.js';
export * from './capitalizeFirstLetter';
+export * from './FileSizeFormatter';
diff --git a/tools/public_api_guard/react-core.api.md b/tools/public_api_guard/react-core.api.md
index abb08250b..427316b33 100644
--- a/tools/public_api_guard/react-core.api.md
+++ b/tools/public_api_guard/react-core.api.md
@@ -104,6 +104,50 @@ export type ExtendableComponentPropsWithRef
// @public (undocumented)
export type ExtendableProps, ExtendedProps = Record> = Merge;
+// @public (undocumented)
+export const FILE_SIZE_FORMATTER_ERROR_PRECISION_RANGE = "FileSizeFormatter: \"precision\" must be an integer between 0 and 100.";
+
+// @public
+export type FileSizeFormatOptions = {
+ precision?: number;
+ unitSystem?: FileSizeMeasurementSystem;
+};
+
+// @public
+export class FileSizeFormatter {
+ constructor(locale?: string, config?: FileSizeFormatterConfig);
+ format(value: number, options?: FileSizeFormatOptions): string;
+}
+
+// @public
+export type FileSizeFormatterConfig = {
+ defaultUnitSystem?: FileSizeMeasurementSystem;
+ defaultPrecision?: number;
+ unitSystems?: Partial>>;
+};
+
+// @public
+export type FileSizeMeasurementSystem = (typeof fileSizeMeasurementSystem)[number];
+
+// @public
+export const fileSizeMeasurementSystem: readonly ["SI", "IEC"];
+
+// @public
+export type FileSizeUnitAbbreviations = readonly [
+string,
+string,
+string,
+string,
+string
+];
+
+// @public
+export type FileSizeUnitSystem = {
+ abbreviations: FileSizeUnitAbbreviations;
+ base: number;
+ power: number;
+};
+
export { filterDOMProps }
export { FocusableElement }
@@ -276,12 +320,12 @@ export { useDescription }
export function useDOMRef(ref?: RefObject_2 | Ref_2): RefObject_2;
// @public
-export function useElementOverflow(): {
- ref: RefObject_2;
- isOverflow: boolean;
- isOverflowX: boolean;
- isOverflowY: boolean;
-};
+export function useElementOverflow(): {
+ ref: RefObject_2;
+ isOverflow: boolean;
+ isOverflowX: boolean;
+ isOverflowY: boolean;
+};
// @public
export function useElementSize(options?: ResizeObserverOptions): {
@@ -307,6 +351,9 @@ export function useEventListener(input: UseEve
// @public (undocumented)
export function useEventListener(input: UseEventListener void, RefObject_2 | undefined>): void;
+// @public
+export function useFileSizeFormatter(config?: FileSizeFormatterConfig): FileSizeFormatter;
+
// @public
export function useHideOverflowItems- (input: UseHideOverflowItemsProps): {
visibleMap: boolean[];