@flipdish/ui-library 0.37.0 → 0.39.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.
- package/README.md +9 -9
- package/dist/components/__internal__/selectionControl/selectionControl.styles.cjs +22 -0
- package/dist/components/__internal__/selectionControl/selectionControl.styles.cjs.map +1 -0
- package/dist/components/__internal__/selectionControl/selectionControl.styles.d.ts +17 -0
- package/dist/components/__internal__/selectionControl/selectionControl.styles.d.ts.map +1 -0
- package/dist/components/__internal__/selectionControl/selectionControl.styles.js +20 -0
- package/dist/components/__internal__/selectionControl/selectionControl.styles.js.map +1 -0
- package/dist/components/__internal__/selectionControl/selectionControl.utils.d.ts +23 -0
- package/dist/components/__internal__/selectionControl/selectionControl.utils.d.ts.map +1 -0
- package/dist/components/atoms/Checkbox/index.cjs +3 -16
- package/dist/components/atoms/Checkbox/index.cjs.map +1 -1
- package/dist/components/atoms/Checkbox/index.d.ts.map +1 -1
- package/dist/components/atoms/Checkbox/index.js +3 -16
- package/dist/components/atoms/Checkbox/index.js.map +1 -1
- package/dist/components/atoms/Toggle/Toggle.styles.cjs +0 -14
- package/dist/components/atoms/Toggle/Toggle.styles.cjs.map +1 -1
- package/dist/components/atoms/Toggle/Toggle.styles.d.ts +0 -14
- package/dist/components/atoms/Toggle/Toggle.styles.d.ts.map +1 -1
- package/dist/components/atoms/Toggle/Toggle.styles.js +0 -14
- package/dist/components/atoms/Toggle/Toggle.styles.js.map +1 -1
- package/dist/components/atoms/Toggle/index.cjs +3 -2
- package/dist/components/atoms/Toggle/index.cjs.map +1 -1
- package/dist/components/atoms/Toggle/index.d.ts.map +1 -1
- package/dist/components/atoms/Toggle/index.js +3 -2
- package/dist/components/atoms/Toggle/index.js.map +1 -1
- package/dist/components/templates/WidgetLayout/index.cjs +36 -0
- package/dist/components/templates/WidgetLayout/index.cjs.map +1 -0
- package/dist/components/templates/WidgetLayout/index.d.ts +54 -0
- package/dist/components/templates/WidgetLayout/index.d.ts.map +1 -0
- package/dist/components/templates/WidgetLayout/index.js +34 -0
- package/dist/components/templates/WidgetLayout/index.js.map +1 -0
- package/dist/native/components/__internal__/selectionControl/SelectionControlText.d.ts +1 -1
- package/dist/native/components/__internal__/selectionControl/SelectionControlText.d.ts.map +1 -1
- package/dist/native/components/__internal__/selectionControl/SelectionControlText.js +2 -1
- package/dist/native/components/__internal__/selectionControl/SelectionControlText.js.map +1 -1
- package/dist/native/components/__internal__/selectionControl/selectionControl.styles.d.ts +17 -0
- package/dist/native/components/__internal__/selectionControl/selectionControl.styles.d.ts.map +1 -0
- package/dist/native/components/__internal__/selectionControl/selectionControl.styles.js +20 -0
- package/dist/native/components/__internal__/selectionControl/selectionControl.styles.js.map +1 -0
- package/dist/native/components/__internal__/selectionControl/selectionControl.utils.d.ts +23 -0
- package/dist/native/components/__internal__/selectionControl/selectionControl.utils.d.ts.map +1 -0
- package/dist/native/components/__internal__/selectionControl/selectionControl.utils.js +20 -0
- package/dist/native/components/__internal__/selectionControl/selectionControl.utils.js.map +1 -0
- package/dist/native/components/atoms/Checkbox/index.d.ts +31 -9
- package/dist/native/components/atoms/Checkbox/index.d.ts.map +1 -0
- package/dist/native/components/atoms/Checkbox/index.js +39 -0
- package/dist/native/components/atoms/Checkbox/index.js.map +1 -0
- package/dist/native/components/atoms/Toggle/Toggle.styles.d.ts +0 -14
- package/dist/native/components/atoms/Toggle/Toggle.styles.d.ts.map +1 -1
- package/dist/native/components/atoms/Toggle/Toggle.styles.js +0 -14
- package/dist/native/components/atoms/Toggle/Toggle.styles.js.map +1 -1
- package/dist/native/components/atoms/Toggle/index.d.ts.map +1 -1
- package/dist/native/components/atoms/Toggle/index.js +3 -1
- package/dist/native/components/atoms/Toggle/index.js.map +1 -1
- package/dist/native/components/templates/WidgetLayout/index.d.ts +12 -0
- package/dist/providers/PortalContainer/index.d.ts +1 -1
- package/dist/providers/ThemeProvider/index.cjs +36 -14
- package/dist/providers/ThemeProvider/index.cjs.map +1 -1
- package/dist/providers/ThemeProvider/index.d.ts +19 -5
- package/dist/providers/ThemeProvider/index.d.ts.map +1 -1
- package/dist/providers/ThemeProvider/index.js +36 -14
- package/dist/providers/ThemeProvider/index.js.map +1 -1
- package/dist/providers/UIProvider/hooks/usePortalAnchor.cjs +137 -0
- package/dist/providers/UIProvider/hooks/usePortalAnchor.cjs.map +1 -0
- package/dist/providers/UIProvider/hooks/usePortalAnchor.d.ts +60 -0
- package/dist/providers/UIProvider/hooks/usePortalAnchor.d.ts.map +1 -0
- package/dist/providers/UIProvider/hooks/usePortalAnchor.js +131 -0
- package/dist/providers/UIProvider/hooks/usePortalAnchor.js.map +1 -0
- package/dist/providers/UIProvider/index.cjs +7 -64
- package/dist/providers/UIProvider/index.cjs.map +1 -1
- package/dist/providers/UIProvider/index.d.ts +16 -11
- package/dist/providers/UIProvider/index.d.ts.map +1 -1
- package/dist/providers/UIProvider/index.js +7 -64
- package/dist/providers/UIProvider/index.js.map +1 -1
- package/dist/utilities/cssScopeUtils/index.cjs +22 -11
- package/dist/utilities/cssScopeUtils/index.cjs.map +1 -1
- package/dist/utilities/cssScopeUtils/index.d.ts +20 -9
- package/dist/utilities/cssScopeUtils/index.d.ts.map +1 -1
- package/dist/utilities/cssScopeUtils/index.js +22 -11
- package/dist/utilities/cssScopeUtils/index.js.map +1 -1
- package/dist/utilities/renderUtils/index.cjs +36 -7
- package/dist/utilities/renderUtils/index.cjs.map +1 -1
- package/dist/utilities/renderUtils/index.d.ts +23 -2
- package/dist/utilities/renderUtils/index.d.ts.map +1 -1
- package/dist/utilities/renderUtils/index.js +35 -8
- package/dist/utilities/renderUtils/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectionControlText.d.ts","sourceRoot":"","sources":["../../../../../src/components/__internal__/selectionControl/SelectionControlText.native.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SelectionControlText.d.ts","sourceRoot":"","sources":["../../../../../src/components/__internal__/selectionControl/SelectionControlText.native.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAE,KAAK,oBAAoB,EAAyB,MAAM,2BAA2B,CAAC;AAa7F,UAAU,yBAAyB;IACjC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,yHAAyH;AACzH,eAAO,MAAM,oBAAoB,GAAI,uBAAuB,yBAAyB,uCASpF,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { cx } from '../../../utilities/cx/index.js';
|
|
3
3
|
import { View, Text } from 'react-native';
|
|
4
|
+
import { selectionControlSizes } from './selectionControl.styles.js';
|
|
4
5
|
|
|
5
6
|
// `Text` className is ignored by the current `react-native-css` preview (see Avatar), so label
|
|
6
7
|
// typography goes through `style`. Mirrors `text-sm`/`text-md` + `font-medium`.
|
|
@@ -15,7 +16,7 @@ const HINT_COLOR = '#525252';
|
|
|
15
16
|
const SelectionControlText = ({ size, label, hint }) => {
|
|
16
17
|
if (!label && !hint)
|
|
17
18
|
return null;
|
|
18
|
-
return (jsxs(View, { className: cx('shrink flex-col', size
|
|
19
|
+
return (jsxs(View, { className: cx('shrink flex-col', selectionControlSizes[size].textWrapper), children: [label ? jsx(Text, { style: { ...TEXT_SIZE[size], fontWeight: '500', color: LABEL_COLOR }, children: label }) : null, hint ? jsx(Text, { style: { ...TEXT_SIZE[size], color: HINT_COLOR }, children: hint }) : null] }));
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export { SelectionControlText };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectionControlText.js","sources":["../../../../../../src/components/__internal__/selectionControl/SelectionControlText.native.tsx"],"sourcesContent":[null],"names":["_jsxs","_jsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"SelectionControlText.js","sources":["../../../../../../src/components/__internal__/selectionControl/SelectionControlText.native.tsx"],"sourcesContent":[null],"names":["_jsxs","_jsx"],"mappings":";;;;;AAKA;AACA;AACA,MAAM,SAAS,GAA2E;IACxF,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;IACpC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;CACrC;AAED;AACA,MAAM,WAAW,GAAG,SAAS;AAC7B,MAAM,UAAU,GAAG,SAAS;AAQ5B;AACO,MAAM,oBAAoB,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAA6B,KAAI;AACvF,IAAA,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;AAEhC,IAAA,QACEA,IAAA,CAAC,IAAI,EAAA,EAAC,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,EAAA,QAAA,EAAA,CAC5E,KAAK,GAAGC,GAAA,CAAC,IAAI,EAAA,EAAC,KAAK,EAAE,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAA,QAAA,EAAG,KAAK,EAAA,CAAQ,GAAG,IAAI,EACzG,IAAI,GAAGA,IAAC,IAAI,EAAA,EAAC,KAAK,EAAE,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAA,QAAA,EAAG,IAAI,GAAQ,GAAG,IAAI,CAAA,EAAA,CAC/E;AAEX;;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type SelectionControlSize = 'sm' | 'md';
|
|
2
|
+
/** Root gap and label/hint typography shared by `Toggle`, `Checkbox` and `RadioButton` on web and React Native. */
|
|
3
|
+
export declare const selectionControlSizes: {
|
|
4
|
+
sm: {
|
|
5
|
+
root: string;
|
|
6
|
+
textWrapper: string;
|
|
7
|
+
label: string;
|
|
8
|
+
hint: string;
|
|
9
|
+
};
|
|
10
|
+
md: {
|
|
11
|
+
root: string;
|
|
12
|
+
textWrapper: string;
|
|
13
|
+
label: string;
|
|
14
|
+
hint: string;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=selectionControl.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectionControl.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/__internal__/selectionControl/selectionControl.styles.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/C,mHAAmH;AACnH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CAakE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { sortCx } from '../../../utilities/cx/index.js';
|
|
2
|
+
|
|
3
|
+
/** Root gap and label/hint typography shared by `Toggle`, `Checkbox` and `RadioButton` on web and React Native. */
|
|
4
|
+
const selectionControlSizes = sortCx({
|
|
5
|
+
sm: {
|
|
6
|
+
root: 'gap-2',
|
|
7
|
+
textWrapper: '',
|
|
8
|
+
label: 'text-sm font-medium',
|
|
9
|
+
hint: 'text-sm',
|
|
10
|
+
},
|
|
11
|
+
md: {
|
|
12
|
+
root: 'gap-3',
|
|
13
|
+
textWrapper: 'gap-0.5',
|
|
14
|
+
label: 'text-md font-medium',
|
|
15
|
+
hint: 'text-md',
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export { selectionControlSizes };
|
|
20
|
+
//# sourceMappingURL=selectionControl.styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectionControl.styles.js","sources":["../../../../../../src/components/__internal__/selectionControl/selectionControl.styles.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAIA;AACO,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC1C,IAAA,EAAE,EAAE;AACF,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,EAAE;AACf,QAAA,KAAK,EAAE,qBAAqB;AAC5B,QAAA,IAAI,EAAE,SAAS;AAChB,KAAA;AACD,IAAA,EAAE,EAAE;AACF,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,SAAS;AACtB,QAAA,KAAK,EAAE,qBAAqB;AAC5B,QAAA,IAAI,EAAE,SAAS;AAChB,KAAA;AACgG,CAAA;;"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Accessible name for a native selection control, since RN's `accessibilityLabel` takes only a string.
|
|
4
|
+
*
|
|
5
|
+
* @param ariaLabel Explicit name from the web-style `aria-label` prop; always wins when set.
|
|
6
|
+
* @param label The visible label, used only when it is plain text.
|
|
7
|
+
* @returns The name to announce, or `undefined` when neither gives a string.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getAccessibleName: (ariaLabel: string | undefined, label: ReactNode) => string | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Screen-reader hint for a native selection control, since RN's `accessibilityHint` takes only a string.
|
|
12
|
+
*
|
|
13
|
+
* @param hint The visible hint, announced after the name only when it is plain text.
|
|
14
|
+
* @returns The hint to announce, or `undefined` for a non-string or missing hint.
|
|
15
|
+
*/
|
|
16
|
+
export declare const getAccessibleHint: (hint: ReactNode) => string | undefined;
|
|
17
|
+
export declare const SELECTION_CONTROL_HIT_SLOP: {
|
|
18
|
+
top: number;
|
|
19
|
+
bottom: number;
|
|
20
|
+
left: number;
|
|
21
|
+
right: number;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=selectionControl.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectionControl.utils.d.ts","sourceRoot":"","sources":["../../../../../src/components/__internal__/selectionControl/selectionControl.utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,GAAG,SAAS,EAAE,OAAO,SAAS,KAAG,MAAM,GAAG,SAC/B,CAAC;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,SAAS,KAAG,MAAM,GAAG,SAA0D,CAAC;AAGxH,eAAO,MAAM,0BAA0B;;;;;CAA6C,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessible name for a native selection control, since RN's `accessibilityLabel` takes only a string.
|
|
3
|
+
*
|
|
4
|
+
* @param ariaLabel Explicit name from the web-style `aria-label` prop; always wins when set.
|
|
5
|
+
* @param label The visible label, used only when it is plain text.
|
|
6
|
+
* @returns The name to announce, or `undefined` when neither gives a string.
|
|
7
|
+
*/
|
|
8
|
+
const getAccessibleName = (ariaLabel, label) => ariaLabel ?? (typeof label === 'string' ? label : undefined);
|
|
9
|
+
/**
|
|
10
|
+
* Screen-reader hint for a native selection control, since RN's `accessibilityHint` takes only a string.
|
|
11
|
+
*
|
|
12
|
+
* @param hint The visible hint, announced after the name only when it is plain text.
|
|
13
|
+
* @returns The hint to announce, or `undefined` for a non-string or missing hint.
|
|
14
|
+
*/
|
|
15
|
+
const getAccessibleHint = (hint) => (typeof hint === 'string' ? hint : undefined);
|
|
16
|
+
// Widens the 16–24px controls toward the 44pt minimum; vertical stops at 8 so options in a `gap-4` stack never overlap.
|
|
17
|
+
const SELECTION_CONTROL_HIT_SLOP = { top: 8, bottom: 8, left: 12, right: 12 };
|
|
18
|
+
|
|
19
|
+
export { SELECTION_CONTROL_HIT_SLOP, getAccessibleHint, getAccessibleName };
|
|
20
|
+
//# sourceMappingURL=selectionControl.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectionControl.utils.js","sources":["../../../../../../src/components/__internal__/selectionControl/selectionControl.utils.ts"],"sourcesContent":[null],"names":[],"mappings":"AAEA;;;;;;AAMG;AACI,MAAM,iBAAiB,GAAG,CAAC,SAA6B,EAAE,KAAgB,KAC/E,SAAS,KAAK,OAAO,KAAK,KAAK,QAAQ,GAAG,KAAK,GAAG,SAAS;AAE7D;;;;;AAKG;MACU,iBAAiB,GAAG,CAAC,IAAe,MAA0B,OAAO,IAAI,KAAK,QAAQ,GAAG,IAAI,GAAG,SAAS;AAEtH;MACa,0BAA0B,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE;;"}
|
|
@@ -1,12 +1,34 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface CheckboxProps {
|
|
3
|
+
/** Sets the box size and the label and hint text size. */
|
|
4
|
+
size?: 'sm' | 'md';
|
|
5
|
+
/** Text shown beside the box; pressing it toggles the checkbox. */
|
|
6
|
+
label?: ReactNode;
|
|
7
|
+
/** Supporting text shown below the label. */
|
|
8
|
+
hint?: ReactNode;
|
|
9
|
+
/** Controlled checked state — the checkbox is checked when true. */
|
|
10
|
+
isSelected?: boolean;
|
|
11
|
+
/** Initial checked state for uncontrolled usage. */
|
|
12
|
+
defaultSelected?: boolean;
|
|
13
|
+
/** Shows a dash instead of a check, for a parent whose children are partly checked. */
|
|
14
|
+
isIndeterminate?: boolean;
|
|
15
|
+
/** Disables interaction and shows a reduced-opacity state. */
|
|
16
|
+
isDisabled?: boolean;
|
|
17
|
+
/** Called with the new checked state whenever the user toggles it. */
|
|
18
|
+
onChange?: (isSelected: boolean) => void;
|
|
19
|
+
/** Extra classes merged onto the root `Pressable`. */
|
|
20
|
+
className?: string;
|
|
21
|
+
/** Web-style accessible name, used as `accessibilityLabel` so shared call sites work on both platforms. */
|
|
22
|
+
'aria-label'?: string;
|
|
23
|
+
/** Overrides the generated `testID` (defaults to `fd-checkbox`). */
|
|
24
|
+
'data-testid'?: string;
|
|
25
|
+
}
|
|
1
26
|
/**
|
|
2
|
-
* `Checkbox`
|
|
27
|
+
* React Native `Checkbox` — the same box, check, dash, label and hint as web, built from
|
|
28
|
+
* `Pressable` and `View` instead of a react-aria `Checkbox`. The web `ring-inset` becomes a
|
|
29
|
+
* 1px border, which takes no extra space inside the fixed-size box.
|
|
3
30
|
*
|
|
4
|
-
*
|
|
5
|
-
* that importing `@flipdish/ui-library/components/atoms/Checkbox` from React Native fails at
|
|
6
|
-
* compile time rather than resolving to the web build's types. There is no
|
|
7
|
-
* matching `index.js`, so Metro cannot bundle this module either.
|
|
8
|
-
*
|
|
9
|
-
* To make `Checkbox` available on React Native, add an `index.native.tsx` beside
|
|
10
|
-
* its `index.tsx` — the build picks it up automatically and this stub disappears.
|
|
31
|
+
* @summary checkbox for selecting one or more options (React Native)
|
|
11
32
|
*/
|
|
12
|
-
export declare const
|
|
33
|
+
export declare const Checkbox: ({ label, hint, size, className, isSelected: isSelectedProp, defaultSelected, isIndeterminate, isDisabled, onChange, "aria-label": ariaLabel, "data-testid": dataTestId, }: CheckboxProps) => import("react").JSX.Element;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/atoms/Checkbox/index.native.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAMjD,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,oEAAoE;IACpE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uFAAuF;IACvF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AASD;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,GAAI,2KAYtB,aAAa,gCA4Cf,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Minus, Check } from '@flipdish/ui-icons';
|
|
3
|
+
import { cx } from '../../../utilities/cx/index.js';
|
|
4
|
+
import { useResolvedTestId } from '../../../utilities/testIdUtils/index.js';
|
|
5
|
+
import { useState } from 'react';
|
|
6
|
+
import { Pressable, View } from 'react-native';
|
|
7
|
+
import { SelectionControlText } from '../../__internal__/selectionControl/SelectionControlText.js';
|
|
8
|
+
import { selectionControlSizes } from '../../__internal__/selectionControl/selectionControl.styles.js';
|
|
9
|
+
import { SELECTION_CONTROL_HIT_SLOP, getAccessibleHint, getAccessibleName } from '../../__internal__/selectionControl/selectionControl.utils.js';
|
|
10
|
+
|
|
11
|
+
// Web draws both glyphs in a 14px viewBox with a 2px stroke; the ported 24px icons need 24/7 for the same weight.
|
|
12
|
+
const GLYPH_STROKE = 24 / 7;
|
|
13
|
+
const CHECK_SIZE = { sm: 12, md: 14 };
|
|
14
|
+
const DASH_SIZE = { sm: 10, md: 14 };
|
|
15
|
+
// `text-fg-white` — icons take a colour value, not a class.
|
|
16
|
+
const GLYPH_COLOR = '#ffffff';
|
|
17
|
+
/**
|
|
18
|
+
* React Native `Checkbox` — the same box, check, dash, label and hint as web, built from
|
|
19
|
+
* `Pressable` and `View` instead of a react-aria `Checkbox`. The web `ring-inset` becomes a
|
|
20
|
+
* 1px border, which takes no extra space inside the fixed-size box.
|
|
21
|
+
*
|
|
22
|
+
* @summary checkbox for selecting one or more options (React Native)
|
|
23
|
+
*/
|
|
24
|
+
const Checkbox = ({ label, hint, size = 'sm', className, isSelected: isSelectedProp, defaultSelected = false, isIndeterminate, isDisabled, onChange, 'aria-label': ariaLabel, 'data-testid': dataTestId, }) => {
|
|
25
|
+
const checkboxTestId = useResolvedTestId({ testId: dataTestId, segment: 'checkbox', rootName: 'checkbox' });
|
|
26
|
+
const [uncontrolledSelected, setUncontrolledSelected] = useState(defaultSelected);
|
|
27
|
+
const isSelected = isSelectedProp ?? uncontrolledSelected;
|
|
28
|
+
const isFilled = isSelected || isIndeterminate;
|
|
29
|
+
const handlePress = () => {
|
|
30
|
+
const next = !isSelected;
|
|
31
|
+
if (isSelectedProp === undefined)
|
|
32
|
+
setUncontrolledSelected(next);
|
|
33
|
+
onChange?.(next);
|
|
34
|
+
};
|
|
35
|
+
return (jsxs(Pressable, { testID: checkboxTestId, disabled: isDisabled, onPress: handlePress, accessibilityRole: "checkbox", hitSlop: SELECTION_CONTROL_HIT_SLOP, accessibilityLabel: getAccessibleName(ariaLabel, label), accessibilityHint: getAccessibleHint(hint), accessibilityState: { checked: isIndeterminate ? 'mixed' : isSelected, disabled: Boolean(isDisabled) }, className: cx('relative flex flex-row items-start self-start', selectionControlSizes[size].root, className), children: [jsx(View, { className: cx('size-4 shrink-0 items-center justify-center rounded border border-primary bg-primary', size === 'md' && 'size-5 rounded-md', isFilled && 'border-brand-solid bg-brand-solid', isDisabled && 'opacity-50', isDisabled && !isFilled && 'bg-tertiary', (label || hint) && 'mt-0.5'), children: isIndeterminate ? (jsx(Minus, { size: DASH_SIZE[size], color: GLYPH_COLOR, strokeWidth: GLYPH_STROKE })) : isSelected ? (jsx(Check, { size: CHECK_SIZE[size], color: GLYPH_COLOR, strokeWidth: GLYPH_STROKE })) : null }), jsx(SelectionControlText, { size: size, label: label, hint: hint })] }));
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export { Checkbox };
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../../src/components/atoms/Checkbox/index.native.tsx"],"sourcesContent":[null],"names":["_jsxs","_jsx"],"mappings":";;;;;;;;;;AAkCA;AACA,MAAM,YAAY,GAAG,EAAE,GAAG,CAAC;AAC3B,MAAM,UAAU,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAW;AAC9C,MAAM,SAAS,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAW;AAC7C;AACA,MAAM,WAAW,GAAG,SAAS;AAE7B;;;;;;AAMG;AACI,MAAM,QAAQ,GAAG,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,IAAI,GAAG,IAAI,EACX,SAAS,EACT,UAAU,EAAE,cAAc,EAC1B,eAAe,GAAG,KAAK,EACvB,eAAe,EACf,UAAU,EACV,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,aAAa,EAAE,UAAU,GACX,KAAI;AAClB,IAAA,MAAM,cAAc,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;IAC3G,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GAAG,QAAQ,CAAC,eAAe,CAAC;AACjF,IAAA,MAAM,UAAU,GAAG,cAAc,IAAI,oBAAoB;AACzD,IAAA,MAAM,QAAQ,GAAG,UAAU,IAAI,eAAe;IAE9C,MAAM,WAAW,GAAG,MAAK;AACvB,QAAA,MAAM,IAAI,GAAG,CAAC,UAAU;QACxB,IAAI,cAAc,KAAK,SAAS;YAAE,uBAAuB,CAAC,IAAI,CAAC;AAC/D,QAAA,QAAQ,GAAG,IAAI,CAAC;AAClB,IAAA,CAAC;IAED,QACEA,KAAC,SAAS,EAAA,EACR,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,WAAW,EACpB,iBAAiB,EAAC,UAAU,EAC5B,OAAO,EAAE,0BAA0B,EACnC,kBAAkB,EAAE,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,EACvD,iBAAiB,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAC1C,kBAAkB,EAAE,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,GAAG,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,EACtG,SAAS,EAAE,EAAE,CAAC,+CAA+C,EAAE,qBAAqB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,EAAA,QAAA,EAAA,CAE3GC,GAAA,CAAC,IAAI,EAAA,EACH,SAAS,EAAE,EAAE,CACX,sFAAsF,EACtF,IAAI,KAAK,IAAI,IAAI,mBAAmB,EACpC,QAAQ,IAAI,mCAAmC,EAC/C,UAAU,IAAI,YAAY,EAC1B,UAAU,IAAI,CAAC,QAAQ,IAAI,aAAa,EACxC,CAAC,KAAK,IAAI,IAAI,KAAK,QAAQ,CAC5B,YAEA,eAAe,IACdA,IAAC,KAAK,EAAA,EAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAA,CAAI,IAC7E,UAAU,IACZA,GAAA,CAAC,KAAK,EAAA,EAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAA,CAAI,IAC9E,IAAI,EAAA,CACH,EAEPA,IAAC,oBAAoB,EAAA,EAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAA,CAAI,CAAA,EAAA,CACpD;AAEhB;;"}
|
|
@@ -17,19 +17,5 @@ export declare const styles: {
|
|
|
17
17
|
sm: string;
|
|
18
18
|
md: string;
|
|
19
19
|
};
|
|
20
|
-
sizes: {
|
|
21
|
-
sm: {
|
|
22
|
-
root: string;
|
|
23
|
-
textWrapper: string;
|
|
24
|
-
label: string;
|
|
25
|
-
hint: string;
|
|
26
|
-
};
|
|
27
|
-
md: {
|
|
28
|
-
root: string;
|
|
29
|
-
textWrapper: string;
|
|
30
|
-
label: string;
|
|
31
|
-
hint: string;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
20
|
};
|
|
35
21
|
//# sourceMappingURL=Toggle.styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toggle.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/atoms/Toggle/Toggle.styles.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM
|
|
1
|
+
{"version":3,"file":"Toggle.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/atoms/Toggle/Toggle.styles.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;CAmBjB,CAAC"}
|
|
@@ -19,20 +19,6 @@ const styles = sortCx({
|
|
|
19
19
|
sm: 'translate-x-4',
|
|
20
20
|
md: 'translate-x-5',
|
|
21
21
|
},
|
|
22
|
-
sizes: {
|
|
23
|
-
sm: {
|
|
24
|
-
root: 'gap-2',
|
|
25
|
-
textWrapper: '',
|
|
26
|
-
label: 'text-sm font-medium',
|
|
27
|
-
hint: 'text-sm',
|
|
28
|
-
},
|
|
29
|
-
md: {
|
|
30
|
-
root: 'gap-3',
|
|
31
|
-
textWrapper: 'gap-0.5',
|
|
32
|
-
label: 'text-md font-medium',
|
|
33
|
-
hint: 'text-md',
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
22
|
});
|
|
37
23
|
|
|
38
24
|
export { styles };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toggle.styles.js","sources":["../../../../../../src/components/atoms/Toggle/Toggle.styles.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGO,MAAM,MAAM,GAAG,MAAM,CAAC;AAC3B,IAAA,KAAK,EAAE;AACL,QAAA,OAAO,EAAE;AACP,YAAA,EAAE,EAAE,eAAe;AACnB,YAAA,EAAE,EAAE,gBAAgB;AACrB,SAAA;AACD,QAAA,IAAI,EAAE;AACJ,YAAA,EAAE,EAAE,SAAS;AACb,YAAA,EAAE,EAAE,UAAU;AACf,SAAA;AAC+D,KAAA;AAClE,IAAA,IAAI,EAAE;AACJ,QAAA,EAAE,EAAE,QAAQ;AACZ,QAAA,EAAE,EAAE,QAAQ;AACwB,KAAA;AACtC,IAAA,YAAY,EAAE;AACZ,QAAA,EAAE,EAAE,eAAe;AACnB,QAAA,EAAE,EAAE,eAAe;AACiB,KAAA;
|
|
1
|
+
{"version":3,"file":"Toggle.styles.js","sources":["../../../../../../src/components/atoms/Toggle/Toggle.styles.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGO,MAAM,MAAM,GAAG,MAAM,CAAC;AAC3B,IAAA,KAAK,EAAE;AACL,QAAA,OAAO,EAAE;AACP,YAAA,EAAE,EAAE,eAAe;AACnB,YAAA,EAAE,EAAE,gBAAgB;AACrB,SAAA;AACD,QAAA,IAAI,EAAE;AACJ,YAAA,EAAE,EAAE,SAAS;AACb,YAAA,EAAE,EAAE,UAAU;AACf,SAAA;AAC+D,KAAA;AAClE,IAAA,IAAI,EAAE;AACJ,QAAA,EAAE,EAAE,QAAQ;AACZ,QAAA,EAAE,EAAE,QAAQ;AACwB,KAAA;AACtC,IAAA,YAAY,EAAE;AACZ,QAAA,EAAE,EAAE,eAAe;AACnB,QAAA,EAAE,EAAE,eAAe;AACiB,KAAA;AACvC,CAAA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/atoms/Toggle/index.native.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/atoms/Toggle/index.native.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AAMpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,6DAA6D;IAC7D,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qDAAqD;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAOD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,GAAI,gKAYpB,WAAW,gCA2Eb,CAAC"}
|
|
@@ -4,6 +4,8 @@ import { useResolvedTestId } from '../../../utilities/testIdUtils/index.js';
|
|
|
4
4
|
import { useState, useRef, useEffect } from 'react';
|
|
5
5
|
import { Animated, Easing, Pressable, View } from 'react-native';
|
|
6
6
|
import { SelectionControlText } from '../../__internal__/selectionControl/SelectionControlText.js';
|
|
7
|
+
import { selectionControlSizes } from '../../__internal__/selectionControl/selectionControl.styles.js';
|
|
8
|
+
import { SELECTION_CONTROL_HIT_SLOP, getAccessibleHint } from '../../__internal__/selectionControl/selectionControl.utils.js';
|
|
7
9
|
import { styles } from './Toggle.styles.js';
|
|
8
10
|
|
|
9
11
|
// Matches the web knob's 150ms ease-in-out slide.
|
|
@@ -42,7 +44,7 @@ const Toggle = ({ label, hint, className, size = 'sm', slim, isSelected: isSelec
|
|
|
42
44
|
setUncontrolledSelected(next);
|
|
43
45
|
onChange?.(next);
|
|
44
46
|
};
|
|
45
|
-
return (jsxs(Pressable, { testID: toggleTestId, disabled: isDisabled, onPress: handlePress, onPressIn: () => setPressed(true), onPressOut: () => setPressed(false), accessibilityRole: "switch", accessibilityLabel: ariaLabel ?? label, accessibilityState: { checked: isSelected, disabled: Boolean(isDisabled) }, className: cx('relative flex flex-row items-start self-start',
|
|
47
|
+
return (jsxs(Pressable, { testID: toggleTestId, disabled: isDisabled, onPress: handlePress, onPressIn: () => setPressed(true), onPressOut: () => setPressed(false), accessibilityRole: "switch", hitSlop: SELECTION_CONTROL_HIT_SLOP, accessibilityLabel: ariaLabel ?? label, accessibilityHint: getAccessibleHint(hint), accessibilityState: { checked: isSelected, disabled: Boolean(isDisabled) }, className: cx('relative flex flex-row items-start self-start', selectionControlSizes[size].root, className), children: [jsxs(View, { className: cx('flex-row rounded-full bg-tertiary', isDisabled && 'opacity-50', slim && 'mt-0.5', styles.track[slim ? 'slim' : 'default'][size]), children: [jsx(Animated.View, { pointerEvents: "none", style: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, opacity: progress }, children: jsx(View, { className: cx('flex-1 rounded-full bg-brand-solid', pressed && 'bg-brand-solid_hover') }) }), jsx(View, { pointerEvents: "none", className: cx('absolute inset-0 rounded-full border-secondary', slim && isSelected && 'border-transparent'), style: { borderWidth: slim ? 1 : 0.5 } }), jsx(View, { className: "flex-1 flex-row", onLayout: handleKnobAreaLayout, children: jsx(Animated.View, { style: { transform: [{ translateX }] }, children: jsx(View, { className: cx('rounded-full bg-fg-white shadow-sm', slim && 'border border-toggle-border shadow-xs', slim && isSelected && 'border-toggle-slim-border_pressed', slim && isSelected && pressed && 'border-toggle-slim-border_pressed-hover', styles.knob[size]) }) }) })] }), jsx(SelectionControlText, { size: size, label: label, hint: hint })] }));
|
|
46
48
|
};
|
|
47
49
|
|
|
48
50
|
export { Toggle };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../../src/components/atoms/Toggle/index.native.tsx"],"sourcesContent":[null],"names":["_jsxs","_jsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../../src/components/atoms/Toggle/index.native.tsx"],"sourcesContent":[null],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `WidgetLayout` has no React Native implementation.
|
|
3
|
+
*
|
|
4
|
+
* This is a generated types-only stub (scripts/emit-native-stubs.mjs). It exists so
|
|
5
|
+
* that importing `@flipdish/ui-library/components/templates/WidgetLayout` from React Native fails at
|
|
6
|
+
* compile time rather than resolving to the web build's types. There is no
|
|
7
|
+
* matching `index.js`, so Metro cannot bundle this module either.
|
|
8
|
+
*
|
|
9
|
+
* To make `WidgetLayout` available on React Native, add an `index.native.tsx` beside
|
|
10
|
+
* its `index.tsx` — the build picks it up automatically and this stub disappears.
|
|
11
|
+
*/
|
|
12
|
+
export declare const __NO_REACT_NATIVE_IMPLEMENTATION__: never;
|
|
@@ -19,7 +19,7 @@ export interface PortalContainerProps {
|
|
|
19
19
|
* and is out of scope.
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
|
-
* <PortalContainer getContainer={() => document.getElementById('
|
|
22
|
+
* <PortalContainer getContainer={() => document.getElementById('my-overlay-host')}>
|
|
23
23
|
* <App />
|
|
24
24
|
* </PortalContainer>
|
|
25
25
|
*/
|
|
@@ -17,6 +17,9 @@ const useTheme = () => {
|
|
|
17
17
|
}
|
|
18
18
|
return context;
|
|
19
19
|
};
|
|
20
|
+
// Providers currently mirroring onto <html>, so a page with several (a Storybook docs page mounts one per
|
|
21
|
+
// story) only loses the attribute when the last one unmounts.
|
|
22
|
+
let documentThemeWriters = 0;
|
|
20
23
|
const resolveSystemPreference = () => {
|
|
21
24
|
if (typeof window === 'undefined')
|
|
22
25
|
return 'light';
|
|
@@ -24,15 +27,20 @@ const resolveSystemPreference = () => {
|
|
|
24
27
|
};
|
|
25
28
|
/**
|
|
26
29
|
* Provides light/dark/system theme context, persisted to `localStorage` and following the OS
|
|
27
|
-
* when set to `system`. Renders a `display: contents` wrapper carrying `data-theme`
|
|
28
|
-
* and the Tailwind `dark:` variant cascade,
|
|
30
|
+
* when set to `system`. Renders a `display: contents` wrapper carrying `data-theme` (and
|
|
31
|
+
* `data-mfe-scope` when `scopeId` is set) so tokens and the Tailwind `dark:` variant cascade,
|
|
32
|
+
* including inside CSS-scoped micro-frontends.
|
|
29
33
|
*
|
|
30
34
|
* @summary light/dark/system theme provider carrying data-theme
|
|
31
35
|
*/
|
|
32
|
-
const ThemeProvider = ({ children, defaultTheme = 'system', storageKey
|
|
36
|
+
const ThemeProvider = ({ children, defaultTheme = 'system', storageKey, themeModeOverride, scopeId: scopeIdProp, syncDocumentTheme: syncDocumentThemeProp, }) => {
|
|
37
|
+
// An empty scopeId is unset: it would stamp `data-mfe-scope=""` and switch the <html> mirror off for nothing.
|
|
38
|
+
const scopeId = scopeIdProp || undefined;
|
|
39
|
+
const syncDocumentTheme = syncDocumentThemeProp ?? (themeModeOverride === undefined && scopeId === undefined);
|
|
40
|
+
const resolvedStorageKey = storageKey ?? (scopeId ? `ui-theme:${scopeId}` : 'ui-theme');
|
|
33
41
|
const [theme, setTheme] = React.useState(() => {
|
|
34
42
|
if (typeof window !== 'undefined') {
|
|
35
|
-
const savedTheme = localStorage.getItem(
|
|
43
|
+
const savedTheme = localStorage.getItem(resolvedStorageKey);
|
|
36
44
|
return savedTheme || defaultTheme;
|
|
37
45
|
}
|
|
38
46
|
return defaultTheme;
|
|
@@ -41,24 +49,38 @@ const ThemeProvider = ({ children, defaultTheme = 'system', storageKey = 'ui-the
|
|
|
41
49
|
const [themeRoot, setThemeRoot] = React.useState(null);
|
|
42
50
|
const activeTheme = themeModeOverride ?? theme;
|
|
43
51
|
const resolvedMode = activeTheme === 'system' ? systemPreference : activeTheme;
|
|
52
|
+
// The cleanup removes the attribute, so a host document is left as it was found when the mirror
|
|
53
|
+
// turns off or the provider unmounts.
|
|
44
54
|
React.useEffect(() => {
|
|
55
|
+
if (!syncDocumentTheme)
|
|
56
|
+
return;
|
|
57
|
+
documentThemeWriters += 1;
|
|
45
58
|
document.documentElement.setAttribute('data-theme', resolvedMode);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
return () => {
|
|
60
|
+
documentThemeWriters -= 1;
|
|
61
|
+
if (documentThemeWriters === 0)
|
|
62
|
+
document.documentElement.removeAttribute('data-theme');
|
|
63
|
+
};
|
|
64
|
+
}, [syncDocumentTheme, resolvedMode]);
|
|
65
|
+
// Only persist the theme if it's not overridden
|
|
66
|
+
React.useEffect(() => {
|
|
67
|
+
if (themeModeOverride)
|
|
68
|
+
return;
|
|
69
|
+
if (activeTheme === 'system') {
|
|
70
|
+
localStorage.removeItem(resolvedStorageKey);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
localStorage.setItem(resolvedStorageKey, activeTheme);
|
|
54
74
|
}
|
|
75
|
+
}, [activeTheme, themeModeOverride, resolvedStorageKey]);
|
|
76
|
+
React.useEffect(() => {
|
|
55
77
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
56
78
|
const handleChange = () => setSystemPreference(mediaQuery.matches ? 'dark' : 'light');
|
|
57
79
|
mediaQuery.addEventListener('change', handleChange);
|
|
58
80
|
return () => mediaQuery.removeEventListener('change', handleChange);
|
|
59
|
-
}, [
|
|
81
|
+
}, []);
|
|
60
82
|
const contextValue = React.useMemo(() => ({ theme: activeTheme, setTheme, themeRoot, resolvedMode }), [activeTheme, themeRoot, resolvedMode]);
|
|
61
|
-
return (jsxRuntime.jsx(ThemeContext.Provider, { value: contextValue, children: jsxRuntime.jsx("div", { ref: setThemeRoot, "data-theme": resolvedMode, style: { display: 'contents' }, children: children }) }));
|
|
83
|
+
return (jsxRuntime.jsx(ThemeContext.Provider, { value: contextValue, children: jsxRuntime.jsx("div", { ref: setThemeRoot, "data-theme": resolvedMode, "data-mfe-scope": scopeId, style: { display: 'contents' }, children: children }) }));
|
|
62
84
|
};
|
|
63
85
|
|
|
64
86
|
exports.ThemeProvider = ThemeProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../../src/providers/ThemeProvider/index.tsx"],"sourcesContent":[null],"names":["createContext","useContext","useState","useEffect","useMemo","_jsx"],"mappings":";;;;;AAcA,MAAM,YAAY,GAAGA,mBAAa,CAA+B,SAAS,CAAC;AAE3E;;;;;AAKG;AACI,MAAM,QAAQ,GAAG,MAAuB;AAC7C,IAAA,MAAM,OAAO,GAAGC,gBAAU,CAAC,YAAY,CAAC;AAExC,IAAA,IAAI,OAAO,KAAK,SAAS,EAAE;AACzB,QAAA,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC;IACjE;AAEA,IAAA,OAAO,OAAO;AAChB;AAEA,MAAM,uBAAuB,GAAG,MAAuB;IACrD,IAAI,OAAO,MAAM,KAAK,WAAW;AAAE,QAAA,OAAO,OAAO;AACjD,IAAA,OAAO,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,GAAG,MAAM,GAAG,OAAO;AACrF,CAAC;
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../../src/providers/ThemeProvider/index.tsx"],"sourcesContent":[null],"names":["createContext","useContext","useState","useEffect","useMemo","_jsx"],"mappings":"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"}
|
|
@@ -21,8 +21,9 @@ interface ThemeProviderProps {
|
|
|
21
21
|
*/
|
|
22
22
|
defaultTheme?: Theme;
|
|
23
23
|
/**
|
|
24
|
-
* The key to use to store the theme in localStorage
|
|
25
|
-
*
|
|
24
|
+
* The key to use to store the theme in localStorage. With `scopeId` the default is namespaced so
|
|
25
|
+
* sibling MFEs on one host do not share a key; an explicit key is used as given.
|
|
26
|
+
* @default "ui-theme", or "ui-theme:<scopeId>" when `scopeId` is set
|
|
26
27
|
*/
|
|
27
28
|
storageKey?: string;
|
|
28
29
|
/**
|
|
@@ -30,14 +31,27 @@ interface ThemeProviderProps {
|
|
|
30
31
|
* internal state and skips localStorage persistence — useful for controlled MFE's or tests.
|
|
31
32
|
*/
|
|
32
33
|
themeModeOverride?: 'light' | 'dark';
|
|
34
|
+
/**
|
|
35
|
+
* Stamps `data-mfe-scope={scopeId}` on the themed root so a scoped CSS build
|
|
36
|
+
* (`[data-mfe-scope="sale-service"]`) matches this tree and nothing else on the page.
|
|
37
|
+
*/
|
|
38
|
+
scopeId?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Mirrors `data-theme` onto `<html>` as well as the themed root, and removes it again on unmount or
|
|
41
|
+
* when turned off. An embedded app must not mutate the host document, so this is off whenever
|
|
42
|
+
* `themeModeOverride` or `scopeId` is set.
|
|
43
|
+
* @default true when neither `themeModeOverride` nor `scopeId` is set
|
|
44
|
+
*/
|
|
45
|
+
syncDocumentTheme?: boolean;
|
|
33
46
|
}
|
|
34
47
|
/**
|
|
35
48
|
* Provides light/dark/system theme context, persisted to `localStorage` and following the OS
|
|
36
|
-
* when set to `system`. Renders a `display: contents` wrapper carrying `data-theme`
|
|
37
|
-
* and the Tailwind `dark:` variant cascade,
|
|
49
|
+
* when set to `system`. Renders a `display: contents` wrapper carrying `data-theme` (and
|
|
50
|
+
* `data-mfe-scope` when `scopeId` is set) so tokens and the Tailwind `dark:` variant cascade,
|
|
51
|
+
* including inside CSS-scoped micro-frontends.
|
|
38
52
|
*
|
|
39
53
|
* @summary light/dark/system theme provider carrying data-theme
|
|
40
54
|
*/
|
|
41
|
-
export declare const ThemeProvider: ({ children, defaultTheme, storageKey, themeModeOverride }: ThemeProviderProps) => import("react").JSX.Element;
|
|
55
|
+
export declare const ThemeProvider: ({ children, defaultTheme, storageKey, themeModeOverride, scopeId: scopeIdProp, syncDocumentTheme: syncDocumentThemeProp, }: ThemeProviderProps) => import("react").JSX.Element;
|
|
42
56
|
export {};
|
|
43
57
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/ThemeProvider/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,KAAK,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEzC,UAAU,gBAAgB;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC;AAID;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,QAAO,gBAQ3B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/ThemeProvider/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,KAAK,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEzC,UAAU,gBAAgB;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC;AAID;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,QAAO,gBAQ3B,CAAC;AAWF,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAI,4HAO3B,kBAAkB,gCA0DpB,CAAC"}
|
|
@@ -15,6 +15,9 @@ const useTheme = () => {
|
|
|
15
15
|
}
|
|
16
16
|
return context;
|
|
17
17
|
};
|
|
18
|
+
// Providers currently mirroring onto <html>, so a page with several (a Storybook docs page mounts one per
|
|
19
|
+
// story) only loses the attribute when the last one unmounts.
|
|
20
|
+
let documentThemeWriters = 0;
|
|
18
21
|
const resolveSystemPreference = () => {
|
|
19
22
|
if (typeof window === 'undefined')
|
|
20
23
|
return 'light';
|
|
@@ -22,15 +25,20 @@ const resolveSystemPreference = () => {
|
|
|
22
25
|
};
|
|
23
26
|
/**
|
|
24
27
|
* Provides light/dark/system theme context, persisted to `localStorage` and following the OS
|
|
25
|
-
* when set to `system`. Renders a `display: contents` wrapper carrying `data-theme`
|
|
26
|
-
* and the Tailwind `dark:` variant cascade,
|
|
28
|
+
* when set to `system`. Renders a `display: contents` wrapper carrying `data-theme` (and
|
|
29
|
+
* `data-mfe-scope` when `scopeId` is set) so tokens and the Tailwind `dark:` variant cascade,
|
|
30
|
+
* including inside CSS-scoped micro-frontends.
|
|
27
31
|
*
|
|
28
32
|
* @summary light/dark/system theme provider carrying data-theme
|
|
29
33
|
*/
|
|
30
|
-
const ThemeProvider = ({ children, defaultTheme = 'system', storageKey
|
|
34
|
+
const ThemeProvider = ({ children, defaultTheme = 'system', storageKey, themeModeOverride, scopeId: scopeIdProp, syncDocumentTheme: syncDocumentThemeProp, }) => {
|
|
35
|
+
// An empty scopeId is unset: it would stamp `data-mfe-scope=""` and switch the <html> mirror off for nothing.
|
|
36
|
+
const scopeId = scopeIdProp || undefined;
|
|
37
|
+
const syncDocumentTheme = syncDocumentThemeProp ?? (themeModeOverride === undefined && scopeId === undefined);
|
|
38
|
+
const resolvedStorageKey = storageKey ?? (scopeId ? `ui-theme:${scopeId}` : 'ui-theme');
|
|
31
39
|
const [theme, setTheme] = useState(() => {
|
|
32
40
|
if (typeof window !== 'undefined') {
|
|
33
|
-
const savedTheme = localStorage.getItem(
|
|
41
|
+
const savedTheme = localStorage.getItem(resolvedStorageKey);
|
|
34
42
|
return savedTheme || defaultTheme;
|
|
35
43
|
}
|
|
36
44
|
return defaultTheme;
|
|
@@ -39,24 +47,38 @@ const ThemeProvider = ({ children, defaultTheme = 'system', storageKey = 'ui-the
|
|
|
39
47
|
const [themeRoot, setThemeRoot] = useState(null);
|
|
40
48
|
const activeTheme = themeModeOverride ?? theme;
|
|
41
49
|
const resolvedMode = activeTheme === 'system' ? systemPreference : activeTheme;
|
|
50
|
+
// The cleanup removes the attribute, so a host document is left as it was found when the mirror
|
|
51
|
+
// turns off or the provider unmounts.
|
|
42
52
|
useEffect(() => {
|
|
53
|
+
if (!syncDocumentTheme)
|
|
54
|
+
return;
|
|
55
|
+
documentThemeWriters += 1;
|
|
43
56
|
document.documentElement.setAttribute('data-theme', resolvedMode);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
return () => {
|
|
58
|
+
documentThemeWriters -= 1;
|
|
59
|
+
if (documentThemeWriters === 0)
|
|
60
|
+
document.documentElement.removeAttribute('data-theme');
|
|
61
|
+
};
|
|
62
|
+
}, [syncDocumentTheme, resolvedMode]);
|
|
63
|
+
// Only persist the theme if it's not overridden
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (themeModeOverride)
|
|
66
|
+
return;
|
|
67
|
+
if (activeTheme === 'system') {
|
|
68
|
+
localStorage.removeItem(resolvedStorageKey);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
localStorage.setItem(resolvedStorageKey, activeTheme);
|
|
52
72
|
}
|
|
73
|
+
}, [activeTheme, themeModeOverride, resolvedStorageKey]);
|
|
74
|
+
useEffect(() => {
|
|
53
75
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
54
76
|
const handleChange = () => setSystemPreference(mediaQuery.matches ? 'dark' : 'light');
|
|
55
77
|
mediaQuery.addEventListener('change', handleChange);
|
|
56
78
|
return () => mediaQuery.removeEventListener('change', handleChange);
|
|
57
|
-
}, [
|
|
79
|
+
}, []);
|
|
58
80
|
const contextValue = useMemo(() => ({ theme: activeTheme, setTheme, themeRoot, resolvedMode }), [activeTheme, themeRoot, resolvedMode]);
|
|
59
|
-
return (jsx(ThemeContext.Provider, { value: contextValue, children: jsx("div", { ref: setThemeRoot, "data-theme": resolvedMode, style: { display: 'contents' }, children: children }) }));
|
|
81
|
+
return (jsx(ThemeContext.Provider, { value: contextValue, children: jsx("div", { ref: setThemeRoot, "data-theme": resolvedMode, "data-mfe-scope": scopeId, style: { display: 'contents' }, children: children }) }));
|
|
60
82
|
};
|
|
61
83
|
|
|
62
84
|
export { ThemeProvider, useTheme };
|