@fluentui-react-native/use-tokens 0.1.6

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.
Files changed (106) hide show
  1. package/CHANGELOG.json +200 -0
  2. package/CHANGELOG.md +53 -0
  3. package/README.md +85 -0
  4. package/babel.config.js +1 -0
  5. package/just.config.js +3 -0
  6. package/lib/applyPropsToTokens.d.ts +3 -0
  7. package/lib/applyPropsToTokens.d.ts.map +1 -0
  8. package/lib/applyPropsToTokens.js +28 -0
  9. package/lib/applyPropsToTokens.js.map +1 -0
  10. package/lib/applyPropsToTokens.test.d.ts +2 -0
  11. package/lib/applyPropsToTokens.test.d.ts.map +1 -0
  12. package/lib/applyPropsToTokens.test.js +30 -0
  13. package/lib/applyPropsToTokens.test.js.map +1 -0
  14. package/lib/applyTokenLayers.d.ts +16 -0
  15. package/lib/applyTokenLayers.d.ts.map +1 -0
  16. package/lib/applyTokenLayers.js +25 -0
  17. package/lib/applyTokenLayers.js.map +1 -0
  18. package/lib/applyTokenLayers.test.d.ts +2 -0
  19. package/lib/applyTokenLayers.test.d.ts.map +1 -0
  20. package/lib/applyTokenLayers.test.js +64 -0
  21. package/lib/applyTokenLayers.test.js.map +1 -0
  22. package/lib/buildUseTokens.d.ts +35 -0
  23. package/lib/buildUseTokens.d.ts.map +1 -0
  24. package/lib/buildUseTokens.js +62 -0
  25. package/lib/buildUseTokens.js.map +1 -0
  26. package/lib/buildUseTokens.test.d.ts +2 -0
  27. package/lib/buildUseTokens.test.d.ts.map +1 -0
  28. package/lib/buildUseTokens.test.js +103 -0
  29. package/lib/buildUseTokens.test.js.map +1 -0
  30. package/lib/customizable.d.ts +24 -0
  31. package/lib/customizable.d.ts.map +1 -0
  32. package/lib/customizable.js +22 -0
  33. package/lib/customizable.js.map +1 -0
  34. package/lib/index.d.ts +6 -0
  35. package/lib/index.d.ts.map +1 -0
  36. package/lib/index.js +6 -0
  37. package/lib/index.js.map +1 -0
  38. package/lib/patchTokens.d.ts +12 -0
  39. package/lib/patchTokens.d.ts.map +1 -0
  40. package/lib/patchTokens.js +42 -0
  41. package/lib/patchTokens.js.map +1 -0
  42. package/lib/patchTokens.test.d.ts +2 -0
  43. package/lib/patchTokens.test.d.ts.map +1 -0
  44. package/lib/patchTokens.test.js +38 -0
  45. package/lib/patchTokens.test.js.map +1 -0
  46. package/lib/useTokens.samples.test.d.ts +2 -0
  47. package/lib/useTokens.samples.test.d.ts.map +1 -0
  48. package/lib/useTokens.samples.test.js +165 -0
  49. package/lib/useTokens.samples.test.js.map +1 -0
  50. package/lib-commonjs/applyPropsToTokens.d.ts +3 -0
  51. package/lib-commonjs/applyPropsToTokens.d.ts.map +1 -0
  52. package/lib-commonjs/applyPropsToTokens.js +31 -0
  53. package/lib-commonjs/applyPropsToTokens.js.map +1 -0
  54. package/lib-commonjs/applyPropsToTokens.test.d.ts +2 -0
  55. package/lib-commonjs/applyPropsToTokens.test.d.ts.map +1 -0
  56. package/lib-commonjs/applyPropsToTokens.test.js +32 -0
  57. package/lib-commonjs/applyPropsToTokens.test.js.map +1 -0
  58. package/lib-commonjs/applyTokenLayers.d.ts +16 -0
  59. package/lib-commonjs/applyTokenLayers.d.ts.map +1 -0
  60. package/lib-commonjs/applyTokenLayers.js +28 -0
  61. package/lib-commonjs/applyTokenLayers.js.map +1 -0
  62. package/lib-commonjs/applyTokenLayers.test.d.ts +2 -0
  63. package/lib-commonjs/applyTokenLayers.test.d.ts.map +1 -0
  64. package/lib-commonjs/applyTokenLayers.test.js +66 -0
  65. package/lib-commonjs/applyTokenLayers.test.js.map +1 -0
  66. package/lib-commonjs/buildUseTokens.d.ts +35 -0
  67. package/lib-commonjs/buildUseTokens.d.ts.map +1 -0
  68. package/lib-commonjs/buildUseTokens.js +65 -0
  69. package/lib-commonjs/buildUseTokens.js.map +1 -0
  70. package/lib-commonjs/buildUseTokens.test.d.ts +2 -0
  71. package/lib-commonjs/buildUseTokens.test.d.ts.map +1 -0
  72. package/lib-commonjs/buildUseTokens.test.js +105 -0
  73. package/lib-commonjs/buildUseTokens.test.js.map +1 -0
  74. package/lib-commonjs/customizable.d.ts +24 -0
  75. package/lib-commonjs/customizable.d.ts.map +1 -0
  76. package/lib-commonjs/customizable.js +25 -0
  77. package/lib-commonjs/customizable.js.map +1 -0
  78. package/lib-commonjs/index.d.ts +6 -0
  79. package/lib-commonjs/index.d.ts.map +1 -0
  80. package/lib-commonjs/index.js +11 -0
  81. package/lib-commonjs/index.js.map +1 -0
  82. package/lib-commonjs/patchTokens.d.ts +12 -0
  83. package/lib-commonjs/patchTokens.d.ts.map +1 -0
  84. package/lib-commonjs/patchTokens.js +45 -0
  85. package/lib-commonjs/patchTokens.js.map +1 -0
  86. package/lib-commonjs/patchTokens.test.d.ts +2 -0
  87. package/lib-commonjs/patchTokens.test.d.ts.map +1 -0
  88. package/lib-commonjs/patchTokens.test.js +40 -0
  89. package/lib-commonjs/patchTokens.test.js.map +1 -0
  90. package/lib-commonjs/useTokens.samples.test.d.ts +2 -0
  91. package/lib-commonjs/useTokens.samples.test.d.ts.map +1 -0
  92. package/lib-commonjs/useTokens.samples.test.js +177 -0
  93. package/lib-commonjs/useTokens.samples.test.js.map +1 -0
  94. package/package.json +41 -0
  95. package/src/__snapshots__/useTokens.samples.test.tsx.snap +163 -0
  96. package/src/applyPropsToTokens.test.ts +47 -0
  97. package/src/applyPropsToTokens.ts +15 -0
  98. package/src/applyTokenLayers.test.ts +67 -0
  99. package/src/applyTokenLayers.ts +40 -0
  100. package/src/buildUseTokens.test.ts +113 -0
  101. package/src/buildUseTokens.ts +89 -0
  102. package/src/customizable.ts +36 -0
  103. package/src/index.ts +5 -0
  104. package/src/patchTokens.test.ts +50 -0
  105. package/src/patchTokens.ts +30 -0
  106. package/src/useTokens.samples.test.tsx +219 -0
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __rest = (this && this.__rest) || function (s, e) {
14
+ var t = {};
15
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
16
+ t[p] = s[p];
17
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
18
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
19
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
20
+ t[p[i]] = s[p[i]];
21
+ }
22
+ return t;
23
+ };
24
+ var __importDefault = (this && this.__importDefault) || function (mod) {
25
+ return (mod && mod.__esModule) ? mod : { "default": mod };
26
+ };
27
+ var __importStar = (this && this.__importStar) || function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
31
+ result["default"] = mod;
32
+ return result;
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ var react_native_1 = require("react-native");
36
+ var enzyme_to_json_1 = __importDefault(require("enzyme-to-json"));
37
+ var React = __importStar(require("react"));
38
+ var enzyme_1 = require("enzyme");
39
+ var buildUseTokens_1 = require("./buildUseTokens");
40
+ var merge_props_1 = require("@fluentui-react-native/merge-props");
41
+ var immutable_merge_1 = require("@fluentui-react-native/immutable-merge");
42
+ /**
43
+ * The default/base theme just contains base values
44
+ */
45
+ var baseTheme = {
46
+ globals: {
47
+ backgroundColor: 'white',
48
+ color: 'black',
49
+ borderColor: 'blue',
50
+ fontFamily: 'Arial',
51
+ fontSize: 12,
52
+ },
53
+ components: {},
54
+ };
55
+ var current = { theme: baseTheme };
56
+ var useTheme = function () { return current.theme; };
57
+ var setActiveTheme = function (theme) {
58
+ current.theme = (theme && immutable_merge_1.immutableMerge(baseTheme, theme)) || baseTheme;
59
+ };
60
+ /**
61
+ * this wrapper solves the (so-far) inexplicable type errors from the matchers in typescript
62
+ */
63
+ function snapshotTestTree(tree) {
64
+ expect(enzyme_to_json_1.default(tree)).toMatchSnapshot();
65
+ }
66
+ /**
67
+ * Helper function used to look up a component in the theme. Having this injected allows this module to not be dependent on the shape of
68
+ * the theme used.
69
+ */
70
+ var getComponentInfo = function (theme, name) { return theme.components[name]; };
71
+ describe('useTokens samples', function () {
72
+ /**
73
+ * Sample #1 - Themeable text element
74
+ *
75
+ * This adds some default opinions for how a text element should be styled but only allows for customization
76
+ * via theming
77
+ */
78
+ var useTokensSample1 = buildUseTokens_1.buildUseTokens(getComponentInfo,
79
+ /** first the default values should come from the global theme section */
80
+ function (t) { return ({
81
+ color: t.globals.color,
82
+ fontFamily: t.globals.fontFamily,
83
+ fontSize: t.globals.fontSize,
84
+ }); },
85
+ /** next we should look for a component reference to overlay */
86
+ 'SampleText');
87
+ var SampleText1 = function (props) {
88
+ // standard props splitting
89
+ var style = props.style, children = props.children, rest = __rest(props, ["style", "children"]);
90
+ // typically this would start with a call to retrieve the theme from the context via whatever method is appropriate
91
+ var theme = useTheme();
92
+ // next the tokens are resolved from the theme, a cache specific to this theme is returned as well to allow for
93
+ // style objects to not be rebuilt unnecessarily
94
+ var _a = useTokensSample1(theme), tokens = _a[0], cache = _a[1];
95
+ // build up the text style, or the full props as appropriate
96
+ var styleFromTokens = cache(
97
+ /**
98
+ * first build the style object
99
+ * - this executes once for every unique set of keys.
100
+ * - The cache is already unique for this theme
101
+ */
102
+ function () { return (__assign({}, tokens)); },
103
+ /**
104
+ * now specify the keys
105
+ * - because the only changing variable is the theme
106
+ * - ...and all the style properties are either constant or come from the tokens
107
+ * - ...no keys need to be specified
108
+ * - this means that only one style object will be created per component + theme pair
109
+ */
110
+ []);
111
+ // merge the props from the tokens with anything passed in via style. This is internally cached via object identity
112
+ // so the merged style object won't change identity unless one of the two inputs changes identity.
113
+ var mergedStyle = merge_props_1.mergeStyles(styleFromTokens, style);
114
+ // now just render the element, forwarding the props, setting the merged style, then passing the children as appropriate
115
+ return (React.createElement(react_native_1.Text, __assign({}, rest, { style: mergedStyle }), children));
116
+ };
117
+ beforeEach(function () {
118
+ setActiveTheme();
119
+ });
120
+ /** first render the component with no updates */
121
+ it('Sample1Text rendering with no overrides', function () {
122
+ var tree = enzyme_1.mount(React.createElement(SampleText1, null, "Sample1a"));
123
+ snapshotTestTree(tree);
124
+ });
125
+ /** now re-theme the component via the components in the theme */
126
+ it('Sample1Text rendering with some custom settings in the theme', function () {
127
+ setActiveTheme({
128
+ components: {
129
+ SampleText: {
130
+ color: 'pink',
131
+ fontSize: 24,
132
+ },
133
+ },
134
+ });
135
+ var tree = enzyme_1.mount(React.createElement(SampleText1, null, "Sample1b"));
136
+ snapshotTestTree(tree);
137
+ });
138
+ // the Sample2Text component is built the same way as sample1, just using the new hook that has been created
139
+ var SampleText2 = function (props) {
140
+ var color = props.color, style = props.style, children = props.children, rest = __rest(props, ["color", "style", "children"]);
141
+ var theme = useTheme();
142
+ // this starts the same as sample1, extract tokens from the theme and get a theme specific cache object
143
+ var _a = useTokensSample1(theme), tokens = _a[0], cache = _a[1];
144
+ // now when building up the style this time, the resulting style object is based upon both the theme and the passed
145
+ // in value of colors. Because the theme is already part of the cache definition, only color needs to be a key
146
+ var styleFromTokens = cache(
147
+ /** build the style, only patch the color if it has a value, otherwise the theme value would get stomped if color was undefined */
148
+ function () { return (__assign(__assign({}, tokens), (color && { color: color }))); },
149
+ /** use color as an additional key for the style */
150
+ [color]);
151
+ // now just render, this time merging styles inline to make it a bit shorter
152
+ return (React.createElement(react_native_1.Text, __assign({}, rest, { style: merge_props_1.mergeStyles(styleFromTokens, style) }), children));
153
+ };
154
+ /** rendering the Sample2 component with the base theme */
155
+ it('Sample2Text rendering with defaults and a color override', function () {
156
+ var tree = enzyme_1.mount(React.createElement(react_native_1.View, null,
157
+ React.createElement(SampleText2, null, "Sample2 with defaults"),
158
+ React.createElement(SampleText2, { color: "green" }, "Sample2 with color override via prop")));
159
+ snapshotTestTree(tree);
160
+ });
161
+ /** now re-theme the component via the components in the theme */
162
+ it('Sample2Text rendering with some custom settings in the theme', function () {
163
+ setActiveTheme({
164
+ components: {
165
+ SampleText: {
166
+ fontSize: 18,
167
+ fontFamily: 'Helvetica',
168
+ },
169
+ },
170
+ });
171
+ var tree = enzyme_1.mount(React.createElement(react_native_1.View, null,
172
+ React.createElement(SampleText2, null, "Sample2 with theme overrides set"),
173
+ React.createElement(SampleText2, { color: "purple" }, "Sample2 with theme and color prop override")));
174
+ snapshotTestTree(tree);
175
+ });
176
+ });
177
+ //# sourceMappingURL=useTokens.samples.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTokens.samples.test.js","sourceRoot":"","sources":["../src/useTokens.samples.test.tsx"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@fluentui-react-native/use-tokens",
3
+ "version": "0.1.6",
4
+ "description": "Utilities and hook function for getting themed tokens for a component",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/microsoft/fluentui-react-native"
8
+ },
9
+ "main": "lib-commonjs/index.js",
10
+ "module": "lib/index.js",
11
+ "typings": "lib/index.d.ts",
12
+ "scripts": {
13
+ "build": "fluentui-scripts build",
14
+ "bundle": "fluentui-scripts bundle",
15
+ "clean": "fluentui-scripts clean",
16
+ "code-style": "fluentui-scripts code-style",
17
+ "depcheck": "fluentui-scripts depcheck",
18
+ "just": "fluentui-scripts",
19
+ "lint": "fluentui-scripts eslint",
20
+ "start": "fluentui-scripts dev",
21
+ "start-test": "fluentui-scripts jest-watch",
22
+ "test": "fluentui-scripts jest",
23
+ "update-snapshots": "fluentui-scripts jest -u",
24
+ "prettier": "fluentui-scripts prettier",
25
+ "prettier-fix": "fluentui-scripts prettier --fix true"
26
+ },
27
+ "keywords": [],
28
+ "author": "",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@fluentui-react-native/immutable-merge": "^1.1.3",
32
+ "@fluentui-react-native/memo-cache": "^1.1.4"
33
+ },
34
+ "devDependencies": {
35
+ "@fluentui-react-native/merge-props": "^0.3.4",
36
+ "@types/jest": "^26.0.0",
37
+ "@uifabricshared/build-native": "^0.1.1",
38
+ "react": "16.13.1",
39
+ "react-native": "^0.63.4"
40
+ }
41
+ }
@@ -0,0 +1,163 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`useTokens samples Sample1Text rendering with no overrides 1`] = `
4
+ <SampleText1>
5
+ <Text
6
+ style={
7
+ Object {
8
+ "color": "black",
9
+ "fontFamily": "Arial",
10
+ "fontSize": 12,
11
+ }
12
+ }
13
+ >
14
+ <Text
15
+ style={
16
+ Object {
17
+ "color": "black",
18
+ "fontFamily": "Arial",
19
+ "fontSize": 12,
20
+ }
21
+ }
22
+ >
23
+ Sample1a
24
+ </Text>
25
+ </Text>
26
+ </SampleText1>
27
+ `;
28
+
29
+ exports[`useTokens samples Sample1Text rendering with some custom settings in the theme 1`] = `
30
+ <SampleText1>
31
+ <Text
32
+ style={
33
+ Object {
34
+ "color": "pink",
35
+ "fontFamily": "Arial",
36
+ "fontSize": 24,
37
+ }
38
+ }
39
+ >
40
+ <Text
41
+ style={
42
+ Object {
43
+ "color": "pink",
44
+ "fontFamily": "Arial",
45
+ "fontSize": 24,
46
+ }
47
+ }
48
+ >
49
+ Sample1b
50
+ </Text>
51
+ </Text>
52
+ </SampleText1>
53
+ `;
54
+
55
+ exports[`useTokens samples Sample2Text rendering with defaults and a color override 1`] = `
56
+ <View>
57
+ <View>
58
+ <SampleText2>
59
+ <Text
60
+ style={
61
+ Object {
62
+ "color": "black",
63
+ "fontFamily": "Arial",
64
+ "fontSize": 12,
65
+ }
66
+ }
67
+ >
68
+ <Text
69
+ style={
70
+ Object {
71
+ "color": "black",
72
+ "fontFamily": "Arial",
73
+ "fontSize": 12,
74
+ }
75
+ }
76
+ >
77
+ Sample2 with defaults
78
+ </Text>
79
+ </Text>
80
+ </SampleText2>
81
+ <SampleText2
82
+ color="green"
83
+ >
84
+ <Text
85
+ style={
86
+ Object {
87
+ "color": "green",
88
+ "fontFamily": "Arial",
89
+ "fontSize": 12,
90
+ }
91
+ }
92
+ >
93
+ <Text
94
+ style={
95
+ Object {
96
+ "color": "green",
97
+ "fontFamily": "Arial",
98
+ "fontSize": 12,
99
+ }
100
+ }
101
+ >
102
+ Sample2 with color override via prop
103
+ </Text>
104
+ </Text>
105
+ </SampleText2>
106
+ </View>
107
+ </View>
108
+ `;
109
+
110
+ exports[`useTokens samples Sample2Text rendering with some custom settings in the theme 1`] = `
111
+ <View>
112
+ <View>
113
+ <SampleText2>
114
+ <Text
115
+ style={
116
+ Object {
117
+ "color": "black",
118
+ "fontFamily": "Helvetica",
119
+ "fontSize": 18,
120
+ }
121
+ }
122
+ >
123
+ <Text
124
+ style={
125
+ Object {
126
+ "color": "black",
127
+ "fontFamily": "Helvetica",
128
+ "fontSize": 18,
129
+ }
130
+ }
131
+ >
132
+ Sample2 with theme overrides set
133
+ </Text>
134
+ </Text>
135
+ </SampleText2>
136
+ <SampleText2
137
+ color="purple"
138
+ >
139
+ <Text
140
+ style={
141
+ Object {
142
+ "color": "purple",
143
+ "fontFamily": "Helvetica",
144
+ "fontSize": 18,
145
+ }
146
+ }
147
+ >
148
+ <Text
149
+ style={
150
+ Object {
151
+ "color": "purple",
152
+ "fontFamily": "Helvetica",
153
+ "fontSize": 18,
154
+ }
155
+ }
156
+ >
157
+ Sample2 with theme and color prop override
158
+ </Text>
159
+ </Text>
160
+ </SampleText2>
161
+ </View>
162
+ </View>
163
+ `;
@@ -0,0 +1,47 @@
1
+ import { applyPropsToTokens } from './applyPropsToTokens';
2
+ import { getMemoCache } from '@fluentui-react-native/memo-cache';
3
+
4
+ interface Tokens {
5
+ uno?: string;
6
+ dos?: string;
7
+ tres?: number;
8
+ quatro?: string | number;
9
+ cinco?: boolean;
10
+ }
11
+
12
+ type TokenProps = Pick<Tokens, 'dos' | 'quatro' | 'cinco'>;
13
+ const tokenProps: (keyof TokenProps)[] = ['dos', 'quatro', 'cinco'];
14
+
15
+ interface Props extends TokenProps {
16
+ foo?: string;
17
+ bar?: string;
18
+ }
19
+
20
+ const themeTokens: Tokens = {
21
+ uno: 'uno',
22
+ dos: 'dos',
23
+ tres: 3,
24
+ quatro: 4,
25
+ cinco: true,
26
+ };
27
+
28
+ const props1: Props = { dos: 'two', quatro: 'four', cinco: false, foo: 'foo', bar: 'bar' };
29
+ // const props2: Props = { dos: 'two' };
30
+ // const props3: Props = { foo: 'foo', bar: 'bar' };
31
+
32
+ describe('applyPropsToTokens tests', () => {
33
+ test('props get copied', () => {
34
+ const cache = getMemoCache();
35
+ const [tokens] = applyPropsToTokens(props1, themeTokens, cache, tokenProps);
36
+ expect(tokens).not.toBe(themeTokens);
37
+ for (const key of tokenProps) {
38
+ expect(tokens[key]).toEqual(props1[key]);
39
+ }
40
+ });
41
+
42
+ test('no copied props does not change tokens', () => {
43
+ const cache = getMemoCache();
44
+ const [tokens] = applyPropsToTokens({}, themeTokens, cache, tokenProps);
45
+ expect(tokens).toBe(themeTokens);
46
+ });
47
+ });
@@ -0,0 +1,15 @@
1
+ import { GetMemoValue } from '@fluentui-react-native/memo-cache';
2
+
3
+ export function applyPropsToTokens<TProps, TTokens>(
4
+ props: TProps,
5
+ tokens: TTokens,
6
+ cache: GetMemoValue<TTokens>,
7
+ keys: (keyof TTokens)[],
8
+ ): [TTokens, GetMemoValue<TTokens>] {
9
+ for (const key of keys) {
10
+ const sourceValue = props[key as string];
11
+ const setValue = sourceValue === tokens[key] ? undefined : sourceValue;
12
+ [tokens, cache] = cache(() => (setValue === undefined ? tokens : { ...tokens, [key]: setValue }), [setValue]);
13
+ }
14
+ return [tokens, cache];
15
+ }
@@ -0,0 +1,67 @@
1
+ import { applyTokenLayers } from './applyTokenLayers';
2
+ import { getMemoCache } from '@fluentui-react-native/memo-cache';
3
+
4
+ type Tokens = {
5
+ a?: string;
6
+ b?: string;
7
+ c?: string;
8
+ hover?: Tokens;
9
+ press?: Tokens;
10
+ disabled?: Tokens;
11
+ };
12
+
13
+ const stateOrder = ['hover', 'press', 'disabled'];
14
+
15
+ const tokens1: Tokens = {
16
+ a: 'a',
17
+ b: 'b',
18
+ c: 'c',
19
+ hover: {
20
+ a: 'a-hover',
21
+ b: 'b-hover',
22
+ press: {
23
+ a: 'a-hover-press',
24
+ },
25
+ },
26
+ press: {
27
+ a: 'a-press',
28
+ b: 'b-press',
29
+ },
30
+ disabled: {
31
+ a: 'disabled',
32
+ b: 'disabled',
33
+ c: 'disabled',
34
+ },
35
+ };
36
+
37
+ function stripLayers(tokens: Tokens): Tokens {
38
+ const t = { ...tokens };
39
+ delete t.hover;
40
+ delete t.press;
41
+ delete t.disabled;
42
+ return t;
43
+ }
44
+
45
+ describe('applyLayers tests', () => {
46
+ test('no layers returns tokens', () => {
47
+ const cache = getMemoCache();
48
+ const tokens = applyTokenLayers(tokens1, stateOrder, cache, () => false)[0];
49
+ expect(tokens).toBe(tokens1);
50
+ });
51
+
52
+ test('apply hover works', () => {
53
+ const cache = getMemoCache();
54
+ const lookup = (layer) => layer === 'hover';
55
+ const result1 = applyTokenLayers(tokens1, stateOrder, cache, lookup)[0];
56
+ expect(applyTokenLayers(tokens1, stateOrder, cache, lookup)[0]).toBe(result1);
57
+ expect(stripLayers(result1)).toEqual({ a: 'a-hover', b: 'b-hover', c: 'c' });
58
+ });
59
+
60
+ test('apply hover and press layer correctly', () => {
61
+ const cache = getMemoCache();
62
+ const lookup = (layer) => layer === 'hover' || layer === 'press';
63
+ const result1 = applyTokenLayers(tokens1, stateOrder, cache, lookup)[0];
64
+ expect(applyTokenLayers(tokens1, stateOrder, cache, lookup)[0]).toBe(result1);
65
+ expect(stripLayers(result1)).toEqual({ a: 'a-hover-press', b: 'b-press', c: 'c' });
66
+ });
67
+ });
@@ -0,0 +1,40 @@
1
+ import { GetMemoValue } from '@fluentui-react-native/memo-cache';
2
+ import { immutableMerge } from '@fluentui-react-native/immutable-merge';
3
+
4
+ /**
5
+ * alternatively look them up with a passed in function
6
+ */
7
+ export type HasLayer = (name: string) => boolean;
8
+
9
+ /**
10
+ * Apply token layers, building them up applied layer by applied layer, using the cache to store intermediate
11
+ * values
12
+ *
13
+ * @param tokens - input tokens which may have layers to apply
14
+ * @param states - array of states to check for, ordered by precedence
15
+ * @param subCache - cache scoped to the root object with no layers applied
16
+ * @param hasLayer - a function which returns whether a given layer should be applied
17
+ */
18
+ export function applyTokenLayers<TTokens>(
19
+ tokens: TTokens,
20
+ states: string[],
21
+ subCache: GetMemoValue<TTokens>,
22
+ hasLayer: HasLayer,
23
+ ): [TTokens, GetMemoValue<TTokens>] {
24
+ type TokensAndCache = { tokens: TTokens; subCache: GetMemoValue<TTokens> };
25
+ let final: TokensAndCache = { tokens, subCache };
26
+ if (states && states.length > 0) {
27
+ // now walk the overrides that are set, merging in props, caching results, and getting a new sub cache
28
+ final = states
29
+ .filter((val) => hasLayer(val))
30
+ .reduce((previous: TokensAndCache, layerName: string) => {
31
+ const layer = previous.tokens[layerName];
32
+ const [tokens, subCache] = previous.subCache(
33
+ () => (layer && typeof layer === 'object' ? immutableMerge(previous.tokens, layer) : previous.tokens),
34
+ [layer],
35
+ );
36
+ return { tokens, subCache };
37
+ }, final);
38
+ }
39
+ return [final.tokens, final.subCache];
40
+ }
@@ -0,0 +1,113 @@
1
+ import { buildUseTokens } from './buildUseTokens';
2
+
3
+ interface Tokens {
4
+ a?: string;
5
+ b?: string;
6
+ c?: string;
7
+ hover?: Tokens;
8
+ press?: Tokens;
9
+ }
10
+
11
+ const baseTokens: Tokens = {
12
+ a: 'a-base',
13
+ b: 'b-base',
14
+ c: 'c-base',
15
+ hover: {
16
+ c: 'c-base-hover',
17
+ },
18
+ press: {
19
+ c: 'c-base-press',
20
+ },
21
+ };
22
+
23
+ interface Theme {
24
+ vals: {
25
+ foo?: string;
26
+ bar?: string;
27
+ };
28
+ components: {
29
+ [key: string]: Tokens;
30
+ };
31
+ }
32
+
33
+ const defaultTheme: Theme = {
34
+ vals: {
35
+ foo: 'foo',
36
+ bar: 'bar',
37
+ },
38
+ components: {
39
+ uno: {
40
+ a: 'uno-a',
41
+ c: 'uno-c',
42
+ },
43
+ dos: {
44
+ b: 'dos-b',
45
+ c: 'dos-c',
46
+ },
47
+ },
48
+ };
49
+
50
+ const variantTheme: Theme = {
51
+ vals: {
52
+ foo: 'variant',
53
+ },
54
+ components: {},
55
+ };
56
+
57
+ const getComponentInfo = (theme: Theme, name: string) => theme.components[name];
58
+
59
+ const componentTokens = [baseTokens, 'uno', (theme: Theme) => ({ b: theme.vals.foo })];
60
+
61
+ const resolvedTokens: Tokens = {
62
+ a: 'uno-a',
63
+ b: 'foo',
64
+ c: 'uno-c',
65
+ hover: {
66
+ c: 'c-base-hover',
67
+ },
68
+ press: {
69
+ c: 'c-base-press',
70
+ },
71
+ };
72
+
73
+ const variantTokens: Tokens = {
74
+ a: 'a-base',
75
+ b: 'variant',
76
+ c: 'c-base',
77
+ hover: {
78
+ c: 'c-base-hover',
79
+ },
80
+ press: {
81
+ c: 'c-base-press',
82
+ },
83
+ };
84
+
85
+ describe('buildUseTokens test suite', () => {
86
+ test('basic built hook', () => {
87
+ const useTokens = buildUseTokens(getComponentInfo, ...componentTokens);
88
+ const [tokens] = useTokens(defaultTheme);
89
+ expect(tokens).toEqual(resolvedTokens);
90
+ });
91
+
92
+ test('multiple calls return same object', () => {
93
+ const useTokens = buildUseTokens(getComponentInfo, ...componentTokens);
94
+ const [tokens1] = useTokens(defaultTheme);
95
+ const [tokens2] = useTokens(defaultTheme);
96
+ expect(tokens1).toBe(tokens2);
97
+ });
98
+
99
+ test('variant theme is separate', () => {
100
+ const useTokens = buildUseTokens(getComponentInfo, ...componentTokens);
101
+ const [tokensDefault] = useTokens(defaultTheme);
102
+ const [tokensVariant] = useTokens(variantTheme);
103
+ expect(tokensVariant).not.toBe(tokensDefault);
104
+ expect(tokensVariant).toEqual(variantTokens);
105
+ });
106
+
107
+ test('simple customization layers on top', () => {
108
+ const useTokens = buildUseTokens(getComponentInfo, ...componentTokens);
109
+ const useTokensCustom = useTokens.customize({ a: 'custom' });
110
+ const [tokens] = useTokensCustom(defaultTheme);
111
+ expect(tokens).toEqual({ ...resolvedTokens, a: 'custom' });
112
+ });
113
+ });