handoff-app 0.13.0 → 0.13.2

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/Changelog.md CHANGED
@@ -6,11 +6,32 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to
7
7
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.13.2] - 2024-09-18
10
+
11
+ This release addresses several developer experience issues
12
+
13
+ ### Bugfixes
14
+
15
+ - When an integration compiles SASS code, the token injection was injecting components that had no instances in Figma. This causes integrations to fail if the designer had published a component, but not annotated them in Figma with the plugin. This release checks to see if the component has any instances in the Figma export and skips injection for components that are not yet annotated in Figma
16
+ - When running `eject:integration` or `make:integration` the default integration is exported, but it is not built. This causes a weird developer experience if you try to `build:app` without `build:integration` first. This patch adds the `build:integration` logic to execute after `eject` or `make` as well as before `build:app` to ensure that if an integration exists, the integration is built before building or serving the app
17
+ - If an an `build:app` fails while building the integration preview sass code the error messages were not clear, and didn't explain that you could use `--debug` to make them more clear. The error message has been improved and now alerts users to the `--debug` flag to help them debug their integration.
18
+ - When ejecting an integration with the `--force` flag, the force now triggers an overwrite rather than failing.
19
+
20
+ ## [0.13.1] - 2024-09-17
21
+
22
+ This release fixes a couple of small path issues that affect running 0.13.0 from the global path.
23
+
24
+ ### Bugfixes
25
+
26
+ - Fix a path issue in the ComponentDesignTokens component that causes an error when run from the global namespace
27
+ - Prevents typescript compile errors with the react-scroll `<Link>` component
28
+
9
29
  ## [0.13.0] - 2024-09-08
10
30
 
11
31
  ### Changes
12
32
 
13
33
  - **Integration System Overhaul**
34
+
14
35
  - **Local Integrations Only:** From this release onward, only local (ejected) integrations are supported. Handoff will automatically use the locally found integration.
15
36
  - Create a new local integration using `handoff-app make:integration` (or `eject:integration` which is still supported as an alias).
16
37
  - Since there is no need to specify integration information, integration options in `handoff.config.json` such as name and version are no longer recognized, making the integration section of `handoff.config.json` obsolete.
@@ -40,11 +61,11 @@ and this project adheres to
40
61
  - **For Projects with Legacy Schemas:**
41
62
  1. Eject legacy schemas using `handoff-app eject:exportables`.
42
63
  2. If schemas are already ejected:
43
- - Verify that transformer options are in `integration.config.json`.
44
- - Verify that demo options are in `view.config.json` files of respective components.
45
- - Temporarily rename the directory containing legacy schemas.
46
- - Re-eject schemas and move custom schemas into the new exportables.
47
- - Optionally, update custom schemas to remove obsolete options.
64
+ - Verify that transformer options are in `integration.config.json`.
65
+ - Verify that demo options are in `view.config.json` files of respective components.
66
+ - Temporarily rename the directory containing legacy schemas.
67
+ - Re-eject schemas and move custom schemas into the new exportables.
68
+ - Optionally, update custom schemas to remove obsolete options.
48
69
  - **For Projects with `handoff.config.json`:**
49
70
  1. Merge options from `figma.options` to the `integration.config.json` file as necessary.
50
71
  2. Optionally remove deprecated sections: `figma.options`, `figma.definitions`, `figma`, `integration`, and `use_legacy_definitions`.
@@ -53,122 +74,122 @@ and this project adheres to
53
74
 
54
75
  ### Changes
55
76
 
56
- * Integration bundle used for the docs app is no longer being built during `fetch` and `build:integration` steps.
77
+ - Integration bundle used for the docs app is no longer being built during `fetch` and `build:integration` steps.
57
78
 
58
79
  ## [0.12.1] - 2024-06-18
59
80
 
60
81
  ### Changes
61
82
 
62
- * Added support for the `cssRootClass` property in the Handoff Figma plugin metadata.
83
+ - Added support for the `cssRootClass` property in the Handoff Figma plugin metadata.
63
84
 
64
85
  ### Improvements
65
86
 
66
- * Enhanced handling of unnamed parts, resolving visibility issues in the documentation previews.
87
+ - Enhanced handling of unnamed parts, resolving visibility issues in the documentation previews.
67
88
 
68
89
  ## [0.12.0] - 2024-06-11
69
90
 
70
91
  ### Changes
71
92
 
72
- * All environment variables now contain the `HANDOFF_` prefix.
73
- * After updating to version 0.12.0, all environment variables need to be updated to reflect the new variable names:
74
- * `FIGMA_BASE_URL` -> `HANDOFF_FIGMA_BASE_URL`
75
- * `DEV_ACCESS_TOKEN` -> `HANDOFF_DEV_ACCESS_TOKEN`
76
- * `FIGMA_PROJECT_ID` -> `HANDOFF_FIGMA_PROJECT_ID`
77
- * `OUTPUT_DIR` -> `HANDOFF_OUTPUT_DIR`
78
- * `SITES_DIR` -> `HANDOFF_SITES_DIR`
79
- * `USE_HANDOFF_PLUGIN` -> `HANDOFF_USE_HANDOFF_PLUGIN`
80
- * `CREATE_ASSETS_ZIP_FILES` -> `HANDOFF_CREATE_ASSETS_ZIP_FILES`
81
- * The default integration is no longer pre-defined.
82
- * Bootstrap 5.3 is no longer set as the default integration.
83
- * To continue using the Bootstrap 5.3 integration in your project, ensure the configuration is ejected (`handoff-app eject:config`) and update it by setting the `integration` property to `{name: 'bootstrap', version: '5.3'}`.
84
- * All default options specified in the configuration that are used by the exporter and transformer have been removed.
85
- * To continue using the defaults present before the 0.12.0 release, ensure the configuration is ejected (`handoff-app eject:config`) and update the `figma.options` property to the [previous default value](https://github.com/Convertiv/handoff-app/blob/2a396145e7366732ae6a0e15cdf2226641d40a12/src/config.ts#L36-L59).
86
- * The logo placeholder copy showing spacing and orientation has been removed allowing users to add custom content via Markdown.
93
+ - All environment variables now contain the `HANDOFF_` prefix.
94
+ - After updating to version 0.12.0, all environment variables need to be updated to reflect the new variable names:
95
+ - `FIGMA_BASE_URL` -> `HANDOFF_FIGMA_BASE_URL`
96
+ - `DEV_ACCESS_TOKEN` -> `HANDOFF_DEV_ACCESS_TOKEN`
97
+ - `FIGMA_PROJECT_ID` -> `HANDOFF_FIGMA_PROJECT_ID`
98
+ - `OUTPUT_DIR` -> `HANDOFF_OUTPUT_DIR`
99
+ - `SITES_DIR` -> `HANDOFF_SITES_DIR`
100
+ - `USE_HANDOFF_PLUGIN` -> `HANDOFF_USE_HANDOFF_PLUGIN`
101
+ - `CREATE_ASSETS_ZIP_FILES` -> `HANDOFF_CREATE_ASSETS_ZIP_FILES`
102
+ - The default integration is no longer pre-defined.
103
+ - Bootstrap 5.3 is no longer set as the default integration.
104
+ - To continue using the Bootstrap 5.3 integration in your project, ensure the configuration is ejected (`handoff-app eject:config`) and update it by setting the `integration` property to `{name: 'bootstrap', version: '5.3'}`.
105
+ - All default options specified in the configuration that are used by the exporter and transformer have been removed.
106
+ - To continue using the defaults present before the 0.12.0 release, ensure the configuration is ejected (`handoff-app eject:config`) and update the `figma.options` property to the [previous default value](https://github.com/Convertiv/handoff-app/blob/2a396145e7366732ae6a0e15cdf2226641d40a12/src/config.ts#L36-L59).
107
+ - The logo placeholder copy showing spacing and orientation has been removed allowing users to add custom content via Markdown.
87
108
 
88
109
  ### Improvements
89
110
 
90
- * Handoff now appends to existing `.env` files instead of overriding them if the file already exists.
91
- * Introduced normalization of numeric values in `.css` and `.scss` files, along with correct indentations. This ensures that the generated files are valid for any local linting tools your project might use.
92
- * Configuration ejected by the `handoff-app eject:integration` command is now the same as the one ejected by the `handoff-app eject:config` command.
93
- * Handoff no longer uses the `iframe-resizer` package.
94
- * Resolved potential security issues by updating to newer versions of the `axios` and `next` packages.
111
+ - Handoff now appends to existing `.env` files instead of overriding them if the file already exists.
112
+ - Introduced normalization of numeric values in `.css` and `.scss` files, along with correct indentations. This ensures that the generated files are valid for any local linting tools your project might use.
113
+ - Configuration ejected by the `handoff-app eject:integration` command is now the same as the one ejected by the `handoff-app eject:config` command.
114
+ - Handoff no longer uses the `iframe-resizer` package.
115
+ - Resolved potential security issues by updating to newer versions of the `axios` and `next` packages.
95
116
 
96
117
  ## [0.11.0] - 2024-05-23
97
118
 
98
119
  ### Bugfixes
99
120
 
100
- * Issue that was causing the `handoff-app start` command to malfunction has been fixed.
101
- * The `Reference error: name is not defined` issue that occurred when a component specified in the schema was missing from the Figma file has been resolved. The `name` reference has been replaced with a correct identifier.
102
- * Icon sizes have been corrected.
121
+ - Issue that was causing the `handoff-app start` command to malfunction has been fixed.
122
+ - The `Reference error: name is not defined` issue that occurred when a component specified in the schema was missing from the Figma file has been resolved. The `name` reference has been replaced with a correct identifier.
123
+ - Icon sizes have been corrected.
103
124
 
104
125
  ### Changes
105
126
 
106
- * **Integration with Handoff Figma Plugin**: This release now seamlessly integrates with the Handoff Figma Plugin by default.
107
- * As a result, the local schema will not be used by default.
108
- * If you prefer to continue using local schemas, set `USE_HANDOFF_PLUGIN="FALSE"` in your `.env` file.
109
- * Internal module working directory has been relocated from `./src` to `./.handoff`
127
+ - **Integration with Handoff Figma Plugin**: This release now seamlessly integrates with the Handoff Figma Plugin by default.
128
+ - As a result, the local schema will not be used by default.
129
+ - If you prefer to continue using local schemas, set `USE_HANDOFF_PLUGIN="FALSE"` in your `.env` file.
130
+ - Internal module working directory has been relocated from `./src` to `./.handoff`
110
131
 
111
132
  ## [0.10.0] - 2024-01-16
112
133
 
113
134
  ### Improvements
114
135
 
115
- * Docs App:
116
- * Updated docs app to present components without associated content and assets more elegantly.
117
- * Improved the component pages by showing only the "Tokens" tab when no previews are detected; the "Overview" tab is hidden in such cases.
118
- * Configuration Handling:
119
- * Eliminated the need for `handoff.state.json` file.
120
- * All required parameters are now passed to the docs app through environment variables (`process.env`), defined in the project's respective `next.config.js` file.
121
- * Replaced `getConfig` with the more secure `getClientConfig` function.
122
- * New function returns only configurations that can be safely exposed on the client side.
136
+ - Docs App:
137
+ - Updated docs app to present components without associated content and assets more elegantly.
138
+ - Improved the component pages by showing only the "Tokens" tab when no previews are detected; the "Overview" tab is hidden in such cases.
139
+ - Configuration Handling:
140
+ - Eliminated the need for `handoff.state.json` file.
141
+ - All required parameters are now passed to the docs app through environment variables (`process.env`), defined in the project's respective `next.config.js` file.
142
+ - Replaced `getConfig` with the more secure `getClientConfig` function.
143
+ - New function returns only configurations that can be safely exposed on the client side.
123
144
 
124
145
  ### Changes
125
146
 
126
- * Handoff Figma Plugin Support:
127
- * Introduced initial support for the Handoff Figma Plugin.
128
- * Currently an opt-in feature as development is ongoing.
129
- * Can be enabled by setting `USE_HANDOFF_PLUGIN="TRUE"` in your `.env` file.
130
- * This functionality allows Handoff to extract metadata directly from the Figma file. Local JSON definitions are completely ignored in this case.
131
- * Will become the default behavior in the 1.0.0 release!
132
- * Deprecation Notice:
133
- * Deprecated local exportable component JSON definitions.
134
- * Still usable, but will be completely removed and ignored before the 1.0.0 release.
135
- * Components, parts, and related definitions should be defined with the Handoff Figma Plugin prior to the 1.0.0 release.
147
+ - Handoff Figma Plugin Support:
148
+ - Introduced initial support for the Handoff Figma Plugin.
149
+ - Currently an opt-in feature as development is ongoing.
150
+ - Can be enabled by setting `USE_HANDOFF_PLUGIN="TRUE"` in your `.env` file.
151
+ - This functionality allows Handoff to extract metadata directly from the Figma file. Local JSON definitions are completely ignored in this case.
152
+ - Will become the default behavior in the 1.0.0 release!
153
+ - Deprecation Notice:
154
+ - Deprecated local exportable component JSON definitions.
155
+ - Still usable, but will be completely removed and ignored before the 1.0.0 release.
156
+ - Components, parts, and related definitions should be defined with the Handoff Figma Plugin prior to the 1.0.0 release.
136
157
 
137
158
  ## [0.9.3] - 2023-11-23
138
159
 
139
160
  ### Improvements
140
161
 
141
- * It's now possible to declare conditions for exportable component parts. Condition dictates should the part be built based on provided condition (e.g. does a specific variant property have a certain value etc.).
142
- * Handoff will now process all component sets found within the frame in which the component set that matches the search is found. Previously it was limited to process only one (first) extra component set while others were ignored.
162
+ - It's now possible to declare conditions for exportable component parts. Condition dictates should the part be built based on provided condition (e.g. does a specific variant property have a certain value etc.).
163
+ - Handoff will now process all component sets found within the frame in which the component set that matches the search is found. Previously it was limited to process only one (first) extra component set while others were ignored.
143
164
 
144
165
  ### Changes
145
166
 
146
- * Component preview title will no longer default to the value of the first variant property if no distinctive value is found. Empty value is now used instead.
167
+ - Component preview title will no longer default to the value of the first variant property if no distinctive value is found. Empty value is now used instead.
147
168
 
148
169
  ### Bugfixes
149
170
 
150
- * Update of the app source will now update the watched app without having to restart the watch process (issue introduced in version 0.9.0).
151
-
171
+ - Update of the app source will now update the watched app without having to restart the watch process (issue introduced in version 0.9.0).
152
172
 
153
173
  ## [0.9.2] - 2023-11-21
154
174
 
155
175
  ### Improvements
156
176
 
157
- * Handoff now supports both **personal access** and **OAuth2 bearer** tokens. If Handoff detects that a access token used starts with "Bearer " it will use the `Authorization` header to send the token as part of any Figma API request. In any other case, `X-Figma-Token` header will be used.
177
+ - Handoff now supports both **personal access** and **OAuth2 bearer** tokens. If Handoff detects that a access token used starts with "Bearer " it will use the `Authorization` header to send the token as part of any Figma API request. In any other case, `X-Figma-Token` header will be used.
158
178
 
159
179
  ## [0.9.1] - 2023-11-14
160
180
 
161
181
  ### Changes
162
182
 
163
- * Footer component has been brought back into the app and is now visible on all pages.
164
- * Introduced token maps export feature which exports generated tokens alongside their respective values in form in JSON files (key/value object). Tokens for individual components/foundations are exported into the `tokens/maps` directory of the designated export directory as individual files while the `tokens-map` file, which contains all available tokens, gets exported into the designated export directory root.
183
+ - Footer component has been brought back into the app and is now visible on all pages.
184
+ - Introduced token maps export feature which exports generated tokens alongside their respective values in form in JSON files (key/value object). Tokens for individual components/foundations are exported into the `tokens/maps` directory of the designated export directory as individual files while the `tokens-map` file, which contains all available tokens, gets exported into the designated export directory root.
165
185
 
166
186
  ### Improvements
167
- * Added additional logging into the app's `next.config.js` file alongside improved path resolving for custom themes.
187
+
188
+ - Added additional logging into the app's `next.config.js` file alongside improved path resolving for custom themes.
168
189
 
169
190
  ### Maintenance
170
191
 
171
- * Updated the `.npmignore` file to reflect latest `.gitignore` changes made in the last release.
192
+ - Updated the `.npmignore` file to reflect latest `.gitignore` changes made in the last release.
172
193
 
173
194
  ## [0.9.0] - 2023-11-10
174
195
 
@@ -176,27 +197,27 @@ This release focuses heavily on better support for environments on which multipl
176
197
 
177
198
  ### Changes
178
199
 
179
- * Handoff exports and builds are now updated to support export and build of multiple projects. Each respective output is now located in the subdirectory that matches the exported project id (e.g. /exports/{figmaProjectId}). This change prevents issues where one project would override handoff output of another project in environments where multiple Figma projects are being handled.
180
- * Due to the change in the output directory structure, Bootstrap integration has been updated with a @exported alias which is set to point to export directory of the current project for which the integration is being built.
181
- * Alongside existing support for customized app assets via the `public` directory, it’s now also possible to create a `public-{figmaProjectId}` directory which gets used only when the project with the respective Figma project id is being built. If the `public` directory is used, assets located in that directory will be applied to all projects.
182
- * Handoff state file now always includes the Figma project id.
183
- * Initial anonymization of the config file that gets loaded into the app to prevent secrets from being exposed on the client side.
184
- * Improvements to path resolving for custom app theme(s).
185
- * Restructure and improvements of the configuration:
186
- * `poweredBy` option is now called `attribution` and has been moved into `app` config key.
187
- * `next_base_path` option is now called `base_path` and has been moved into the `app` config key.
188
- * Following options have also been moved into the `app` config key: `theme`, `title`, `client`, `google_tag_manager`, `type_copy`, `type_sort`, `color_sort`, `component_sort`
189
- * `logo` and `favicon` options have been removed (it’s still possible to use custom assets but their name must match the default names).
190
- * Misc.
200
+ - Handoff exports and builds are now updated to support export and build of multiple projects. Each respective output is now located in the subdirectory that matches the exported project id (e.g. /exports/{figmaProjectId}). This change prevents issues where one project would override handoff output of another project in environments where multiple Figma projects are being handled.
201
+ - Due to the change in the output directory structure, Bootstrap integration has been updated with a @exported alias which is set to point to export directory of the current project for which the integration is being built.
202
+ - Alongside existing support for customized app assets via the `public` directory, it’s now also possible to create a `public-{figmaProjectId}` directory which gets used only when the project with the respective Figma project id is being built. If the `public` directory is used, assets located in that directory will be applied to all projects.
203
+ - Handoff state file now always includes the Figma project id.
204
+ - Initial anonymization of the config file that gets loaded into the app to prevent secrets from being exposed on the client side.
205
+ - Improvements to path resolving for custom app theme(s).
206
+ - Restructure and improvements of the configuration:
207
+ - `poweredBy` option is now called `attribution` and has been moved into `app` config key.
208
+ - `next_base_path` option is now called `base_path` and has been moved into the `app` config key.
209
+ - Following options have also been moved into the `app` config key: `theme`, `title`, `client`, `google_tag_manager`, `type_copy`, `type_sort`, `color_sort`, `component_sort`
210
+ - `logo` and `favicon` options have been removed (it’s still possible to use custom assets but their name must match the default names).
211
+ - Misc.
191
212
 
192
213
  ### Bugfixes
193
214
 
194
- * Resolved the wrong favicon path issue when app base path was set/used.
215
+ - Resolved the wrong favicon path issue when app base path was set/used.
195
216
 
196
217
  ### Migrate to a New Version
197
218
 
198
- * Due to the restructure of the configuration, any local configuration (if exists) needs to be updated to match the new structure. Recommended way is to create a backup of the current local configuration(s) and to re-eject of the handoff configuration. Use the backup of the local configuration to update the up-to-date configuration ejected earlier. This process will ensure all the configuration options are defined correctly.
199
- * Since the export and app output directory structures have been updated, any custom script that relies on the old output path(s) should be updated to support new structure that includes the project id subdirectory.
219
+ - Due to the restructure of the configuration, any local configuration (if exists) needs to be updated to match the new structure. Recommended way is to create a backup of the current local configuration(s) and to re-eject of the handoff configuration. Use the backup of the local configuration to update the up-to-date configuration ejected earlier. This process will ensure all the configuration options are defined correctly.
220
+ - Since the export and app output directory structures have been updated, any custom script that relies on the old output path(s) should be updated to support new structure that includes the project id subdirectory.
200
221
 
201
222
  ## [0.8.8] - 2023-10-19
202
223
 
package/dist/app.js CHANGED
@@ -61,6 +61,7 @@ var fs_extra_1 = __importDefault(require("fs-extra"));
61
61
  var chokidar_1 = __importDefault(require("chokidar"));
62
62
  var chalk_1 = __importDefault(require("chalk"));
63
63
  var preview_1 = require("./utils/preview");
64
+ var pipeline_1 = require("./pipeline");
64
65
  var getWorkingPublicPath = function (handoff) {
65
66
  var paths = [
66
67
  path_1.default.resolve(handoff.workingPath, "public-".concat(handoff.config.figma_project_id)),
@@ -147,17 +148,22 @@ var buildApp = function (handoff) { return __awaiter(void 0, void 0, void 0, fun
147
148
  if (!fs_extra_1.default.existsSync(path_1.default.resolve(handoff.workingPath, handoff.exportsDirectory, handoff.config.figma_project_id, 'tokens.json'))) {
148
149
  throw new Error('Tokens not exported. Run `handoff-app fetch` first.');
149
150
  }
151
+ // If we are building the app, ensure the integration is built first
152
+ return [4 /*yield*/, (0, pipeline_1.buildIntegrationOnly)(handoff)];
153
+ case 1:
154
+ // If we are building the app, ensure the integration is built first
155
+ _a.sent();
150
156
  // Build client preview styles
151
157
  return [4 /*yield*/, (0, preview_1.buildClientFiles)(handoff)
152
158
  .then(function (value) { return !!value && console.log(chalk_1.default.green(value)); })
153
159
  .catch(function (error) {
154
160
  throw new Error(error);
155
161
  })];
156
- case 1:
162
+ case 2:
157
163
  // Build client preview styles
158
164
  _a.sent();
159
165
  return [4 /*yield*/, prepareProjectApp(handoff)];
160
- case 2:
166
+ case 3:
161
167
  appPath = _a.sent();
162
168
  // Build app
163
169
  return [4 /*yield*/, (0, next_build_1.nextBuild)({
@@ -168,7 +174,7 @@ var buildApp = function (handoff) { return __awaiter(void 0, void 0, void 0, fun
168
174
  experimentalTurbo: false,
169
175
  experimentalBuildMode: 'default',
170
176
  }, appPath)];
171
- case 3:
177
+ case 4:
172
178
  // Build app
173
179
  _a.sent();
174
180
  outputRoot = path_1.default.resolve(handoff.workingPath, handoff.sitesDirectory);
package/dist/cli/eject.js CHANGED
@@ -45,6 +45,7 @@ var fs_extra_1 = __importDefault(require("fs-extra"));
45
45
  var chalk_1 = __importDefault(require("chalk"));
46
46
  var integration_1 = require("../transformers/integration");
47
47
  var config_1 = require("../config");
48
+ var pipeline_1 = require("../pipeline");
48
49
  /**
49
50
  * Eject the config to the working directory
50
51
  * @param handoff
@@ -72,18 +73,26 @@ exports.ejectConfig = ejectConfig;
72
73
  var makeIntegration = function (handoff) { return __awaiter(void 0, void 0, void 0, function () {
73
74
  var config, workingPath, integrationPath;
74
75
  return __generator(this, function (_a) {
75
- config = handoff.config;
76
- workingPath = path_1.default.resolve(path_1.default.join(handoff.workingPath, 'integration'));
77
- if (fs_extra_1.default.existsSync(workingPath)) {
78
- if (!handoff.force) {
79
- console.log(chalk_1.default.red("An integration already exists in the working directory. Use the --force flag to overwrite."));
80
- return [2 /*return*/];
81
- }
76
+ switch (_a.label) {
77
+ case 0:
78
+ config = handoff.config;
79
+ workingPath = path_1.default.resolve(path_1.default.join(handoff.workingPath, 'integration'));
80
+ if (fs_extra_1.default.existsSync(workingPath)) {
81
+ if (!handoff.force) {
82
+ console.log(chalk_1.default.red("An integration already exists in the working directory. Use the --force flag to overwrite."));
83
+ return [2 /*return*/];
84
+ }
85
+ }
86
+ integrationPath = (0, integration_1.getPathToIntegration)(handoff, true);
87
+ fs_extra_1.default.copySync(integrationPath, workingPath, { overwrite: handoff.force ? true : false });
88
+ if (handoff.force)
89
+ handoff.force = false;
90
+ return [4 /*yield*/, (0, pipeline_1.buildIntegrationOnly)(handoff)];
91
+ case 1:
92
+ _a.sent();
93
+ console.log(chalk_1.default.green("Integration has been successfully created! Path: ".concat(workingPath)));
94
+ return [2 /*return*/, handoff];
82
95
  }
83
- integrationPath = (0, integration_1.getPathToIntegration)(handoff, true);
84
- fs_extra_1.default.copySync(integrationPath, workingPath, { overwrite: false });
85
- console.log(chalk_1.default.green("Integration has been successfully created! Path: ".concat(workingPath)));
86
- return [2 /*return*/, handoff];
87
96
  });
88
97
  }); };
89
98
  exports.makeIntegration = makeIntegration;
package/dist/cli.js CHANGED
@@ -80,7 +80,7 @@ var showHelp = function () {
80
80
  * Show the help message
81
81
  */
82
82
  var showVersion = function () {
83
- cliError('Handoff App - 0.13.0', 2);
83
+ cliError('Handoff App - 0.13.2', 2);
84
84
  };
85
85
  /**
86
86
  * Define a CLI error
package/dist/index.d.ts CHANGED
@@ -56,4 +56,5 @@ declare class Handoff {
56
56
  postIntegration(callback: (documentationObject: DocumentationObject, data: HookReturn[]) => HookReturn[]): void;
57
57
  modifyWebpackConfig(callback: (webpackConfig: webpack.Configuration) => webpack.Configuration): void;
58
58
  }
59
+ export declare const initIntegrationObject: (workingPath: string) => IntegrationObject;
59
60
  export default Handoff;
package/dist/index.js CHANGED
@@ -73,6 +73,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
73
73
  return (mod && mod.__esModule) ? mod : { "default": mod };
74
74
  };
75
75
  Object.defineProperty(exports, "__esModule", { value: true });
76
+ exports.initIntegrationObject = void 0;
76
77
  var config_1 = require("./config");
77
78
  var fs_extra_1 = __importDefault(require("fs-extra"));
78
79
  var path_1 = __importDefault(require("path"));
@@ -117,7 +118,7 @@ var Handoff = /** @class */ (function () {
117
118
  this.config = this.hooks.init(this.config);
118
119
  this.exportsDirectory = (_a = config.exportsOutputDirectory) !== null && _a !== void 0 ? _a : this.exportsDirectory;
119
120
  this.sitesDirectory = (_b = config.sitesOutputDirectory) !== null && _b !== void 0 ? _b : this.exportsDirectory;
120
- this.integrationObject = initIntegrationObject(this.workingPath);
121
+ this.integrationObject = (0, exports.initIntegrationObject)(this.workingPath);
121
122
  return this;
122
123
  };
123
124
  Handoff.prototype.preRunner = function (validate) {
@@ -414,6 +415,7 @@ var initIntegrationObject = function (workingPath) {
414
415
  var integration = JSON.parse(buffer.toString());
415
416
  return (0, integration_2.prepareIntegrationObject)(integration, integrationPath);
416
417
  };
418
+ exports.initIntegrationObject = initIntegrationObject;
417
419
  var validateConfig = function (config) {
418
420
  if (!config.figma_project_id && !process.env.HANDOFF_FIGMA_PROJECT_ID) {
419
421
  // check to see if we can get this from the env
package/dist/pipeline.js CHANGED
@@ -88,6 +88,7 @@ var index_3 = __importStar(require("./transformers/integration/index"));
88
88
  var index_4 = __importDefault(require("./transformers/font/index"));
89
89
  var index_5 = __importDefault(require("./transformers/preview/index"));
90
90
  var app_1 = __importDefault(require("./app"));
91
+ var _1 = require(".");
91
92
  var sd_1 = __importDefault(require("./transformers/sd"));
92
93
  var map_1 = __importDefault(require("./transformers/map"));
93
94
  var lodash_1 = require("lodash");
@@ -433,7 +434,7 @@ var buildRecipe = function (handoff) { return __awaiter(void 0, void 0, void 0,
433
434
  var match;
434
435
  var regex = new RegExp(TOKEN_REGEX, 'g');
435
436
  var _loop_1 = function () {
436
- var _1 = match[0], __ = match[1], component = match[2], part = match[3], variants = match[4], cssProperty = match[5];
437
+ var _2 = match[0], __ = match[1], component = match[2], part = match[3], variants = match[4], cssProperty = match[5];
437
438
  var componentRecord = records.components.find(function (c) { return c.name === component; });
438
439
  if (!componentRecord) {
439
440
  componentRecord = { name: component, common: { parts: [] }, recipes: [] };
@@ -534,6 +535,8 @@ var buildIntegrationOnly = function (handoff) { return __awaiter(void 0, void 0,
534
535
  case 1:
535
536
  documentationObject = _a.sent();
536
537
  if (!documentationObject) return [3 /*break*/, 4];
538
+ // Ensure that the integration object is set if possible
539
+ handoff.integrationObject = (0, _1.initIntegrationObject)(handoff.workingPath);
537
540
  return [4 /*yield*/, buildIntegration(handoff, documentationObject)];
538
541
  case 2:
539
542
  _a.sent();
@@ -86,9 +86,11 @@ var getPathToIntegration = function (handoff, resolveTemplatePath) {
86
86
  if (!handoff) {
87
87
  throw Error('Handoff not initialized');
88
88
  }
89
- var integrationPath = path_1.default.resolve(path_1.default.join(handoff.workingPath, 'integration'));
90
- if (fs_extra_1.default.existsSync(integrationPath)) {
91
- return integrationPath;
89
+ if (!handoff.force) {
90
+ var integrationPath = path_1.default.resolve(path_1.default.join(handoff.workingPath, 'integration'));
91
+ if (fs_extra_1.default.existsSync(integrationPath)) {
92
+ return integrationPath;
93
+ }
92
94
  }
93
95
  if (resolveTemplatePath) {
94
96
  return path_1.default.resolve(path_1.default.join(handoff.modulePath, 'config', 'templates', 'integration'));
@@ -184,7 +186,7 @@ var zipTokens = function (dirPath, destination) { return __awaiter(void 0, void
184
186
  }); };
185
187
  exports.zipTokens = zipTokens;
186
188
  var buildIntegration = function (sourcePath, destPath, documentationObject, rootPath, rootReturnPath) { return __awaiter(void 0, void 0, void 0, function () {
187
- var items, components, _i, items_1, item, sourceItemPath, destItemPath, stat, content, template, renderedContent;
189
+ var items, components, componentsWithInstances, _i, items_1, item, sourceItemPath, destItemPath, stat, content, template, renderedContent;
188
190
  return __generator(this, function (_a) {
189
191
  switch (_a.label) {
190
192
  case 0:
@@ -193,6 +195,7 @@ var buildIntegration = function (sourcePath, destPath, documentationObject, root
193
195
  case 1:
194
196
  items = _a.sent();
195
197
  components = Object.keys(documentationObject.components);
198
+ componentsWithInstances = components.filter(function (component) { return documentationObject.components[component].instances.length > 0; });
196
199
  _i = 0, items_1 = items;
197
200
  _a.label = 2;
198
201
  case 2:
@@ -229,7 +232,7 @@ var buildIntegration = function (sourcePath, destPath, documentationObject, root
229
232
  // Ensure the directory exists before writing the file
230
233
  _a.sent();
231
234
  // Write the rendered content to the destination path
232
- return [4 /*yield*/, fs_extra_1.default.writeFile(destItemPath, replaceHandoffImportTokens(renderedContent, components, path_1.default.parse(destItemPath).dir, rootPath, rootReturnPath !== null && rootReturnPath !== void 0 ? rootReturnPath : '../'))];
235
+ return [4 /*yield*/, fs_extra_1.default.writeFile(destItemPath, replaceHandoffImportTokens(renderedContent, componentsWithInstances, path_1.default.parse(destItemPath).dir, rootPath, rootReturnPath !== null && rootReturnPath !== void 0 ? rootReturnPath : '../'))];
233
236
  case 9:
234
237
  // Write the rendered content to the destination path
235
238
  _a.sent();
@@ -137,18 +137,24 @@ var buildClientFiles = function (handoff) { return __awaiter(void 0, void 0, voi
137
137
  compile.run(function (err, stats) {
138
138
  var _a, _b;
139
139
  if (err) {
140
- var error = 'Errors encountered trying to build preview styles.\n';
140
+ var error = chalk_1.default.red('Errors encountered trying to build preview styles.') + '\n The integration sass expects a token that isn\'t found in your Figma component.\n';
141
141
  if (handoff.debug) {
142
- error += err.stack || err;
142
+ error += chalk_1.default.yellow('\n\n---------- Sass Build Error Trace ---------- \n') + err.stack || err;
143
+ }
144
+ else {
145
+ error += 'Add the --debug flag to see the full error trace\n\n';
143
146
  }
144
147
  return reject(error);
145
148
  }
146
149
  if (stats) {
147
150
  if (stats.hasErrors()) {
148
151
  var buildErrors = (_a = stats.compilation.errors) === null || _a === void 0 ? void 0 : _a.map(function (err) { return err.message; });
149
- var error = 'Errors encountered trying to build preview styles.\n';
152
+ var error = chalk_1.default.red('Errors encountered trying to build preview styles.') + '\nThe integration sass expects a token that isn\'t found in your Figma component.\n';
150
153
  if (handoff.debug) {
151
- error += buildErrors;
154
+ error += chalk_1.default.yellow('\n\n---------- Sass Build Error Trace ---------- \n') + buildErrors;
155
+ }
156
+ else {
157
+ error += 'Add the --debug flag to see the full error trace\n\n';
152
158
  }
153
159
  return reject(error);
154
160
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "handoff-app",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Automated documentation toolchain for building client side documentation from figma",
5
5
  "author ": {
6
6
  "name": "Convertiv",
@@ -11,14 +11,25 @@ export const AnchorNavLink: React.FC<AnchorNavLinkProps> = ({ to, children }) =>
11
11
 
12
12
  useEffect(() => {
13
13
  setOffset(document.getElementById('site-header')?.clientHeight ?? 0);
14
- }, [])
14
+ }, []);
15
15
 
16
16
  return (
17
- <Link href="#" activeClass='is-selected' smooth spy to={to} offset={offset * -1.5} onClick={() => {
18
- history.pushState ? history.pushState(null, '', `#${to}`) : location.hash = `#${to}`;
19
- }}>
20
- {children}
21
- </Link>
17
+ <>
18
+ {/* @ts-ignore */}
19
+ <Link
20
+ href="#"
21
+ activeClass="is-selected"
22
+ smooth
23
+ spy
24
+ to={to}
25
+ offset={offset * -1.5}
26
+ onClick={() => {
27
+ history.pushState ? history.pushState(null, '', `#${to}`) : (location.hash = `#${to}`);
28
+ }}
29
+ >
30
+ {children}
31
+ </Link>
32
+ </>
22
33
  );
23
34
  };
24
35
 
@@ -4,7 +4,7 @@ import React, { useEffect } from 'react';
4
4
  import Icon from './Icon';
5
5
  import { transformComponentTokensToScssVariables } from '@handoff/transformers/scss/component';
6
6
  import { ComponentInstance } from '@handoff/exporters/components/types';
7
- import { IntegrationObjectComponentOptions } from '../../types/config';
7
+ import { IntegrationObjectComponentOptions } from '@handoff/types/config';
8
8
 
9
9
  const PropertyIconPathMap = {
10
10
  'border-width': 'token-border-width',
@@ -7,8 +7,8 @@ import '../sass/main.scss';
7
7
  function MyApp({ Component, pageProps }: AppProps) {
8
8
  return (
9
9
  <>
10
+ {/* @ts-ignore */}
10
11
  <Component {...pageProps} />
11
-
12
12
  </>
13
13
  );
14
14
  }
package/src/app.ts CHANGED
@@ -9,6 +9,7 @@ import fs from 'fs-extra';
9
9
  import chokidar from 'chokidar';
10
10
  import chalk from 'chalk';
11
11
  import { buildClientFiles } from './utils/preview';
12
+ import { buildIntegrationOnly } from './pipeline';
12
13
 
13
14
  const getWorkingPublicPath = (handoff: Handoff): string | null => {
14
15
  const paths = [
@@ -80,6 +81,9 @@ const buildApp = async (handoff: Handoff): Promise<void> => {
80
81
  throw new Error('Tokens not exported. Run `handoff-app fetch` first.');
81
82
  }
82
83
 
84
+ // If we are building the app, ensure the integration is built first
85
+ await buildIntegrationOnly(handoff);
86
+
83
87
  // Build client preview styles
84
88
  await buildClientFiles(handoff)
85
89
  .then((value) => !!value && console.log(chalk.green(value)))
package/src/cli/eject.ts CHANGED
@@ -4,6 +4,7 @@ import fs from 'fs-extra';
4
4
  import chalk from 'chalk';
5
5
  import { getPathToIntegration } from '../transformers/integration';
6
6
  import { getClientConfig } from '../config';
7
+ import { buildIntegrationOnly } from '../pipeline';
7
8
 
8
9
  /**
9
10
  * Eject the config to the working directory
@@ -40,9 +41,10 @@ export const makeIntegration = async (handoff: Handoff) => {
40
41
 
41
42
  // perform integration ejection
42
43
  const integrationPath = getPathToIntegration(handoff, true);
43
- fs.copySync(integrationPath, workingPath, { overwrite: false });
44
+ fs.copySync(integrationPath, workingPath, { overwrite: handoff.force ? true : false });
45
+ if (handoff.force) handoff.force = false;
46
+ await buildIntegrationOnly(handoff);
44
47
  console.log(chalk.green(`Integration has been successfully created! Path: ${workingPath}`));
45
-
46
48
  return handoff;
47
49
  };
48
50
 
package/src/cli.ts CHANGED
@@ -57,7 +57,7 @@ const showHelp = () => {
57
57
  * Show the help message
58
58
  */
59
59
  const showVersion = () => {
60
- cliError('Handoff App - 0.13.0', 2);
60
+ cliError('Handoff App - 0.13.2', 2);
61
61
  };
62
62
 
63
63
  /**
package/src/index.ts CHANGED
@@ -219,7 +219,8 @@ const initConfig = (configOverride?: any): Config => {
219
219
  return returnConfig;
220
220
  };
221
221
 
222
- const initIntegrationObject = (workingPath: string): IntegrationObject => {
222
+
223
+ export const initIntegrationObject = (workingPath: string): IntegrationObject => {
223
224
  const integrationPath = path.join(workingPath, 'integration');
224
225
 
225
226
  if (!fs.existsSync(integrationPath)) {
package/src/pipeline.ts CHANGED
@@ -19,7 +19,7 @@ import integrationTransformer, { getPathToIntegration } from './transformers/int
19
19
  import fontTransformer from './transformers/font/index';
20
20
  import previewTransformer from './transformers/preview/index';
21
21
  import buildApp from './app';
22
- import Handoff from '.';
22
+ import Handoff, { initIntegrationObject } from '.';
23
23
  import sdTransformer from './transformers/sd';
24
24
  import mapTransformer from './transformers/map';
25
25
  import { merge } from 'lodash';
@@ -429,6 +429,8 @@ export const buildRecipe = async (handoff: Handoff) => {
429
429
  export const buildIntegrationOnly = async (handoff: Handoff) => {
430
430
  const documentationObject: DocumentationObject | undefined = await readPrevJSONFile(tokensFilePath(handoff));
431
431
  if (documentationObject) {
432
+ // Ensure that the integration object is set if possible
433
+ handoff.integrationObject = initIntegrationObject(handoff.workingPath);
432
434
  await buildIntegration(handoff, documentationObject);
433
435
  await buildPreviews(handoff, documentationObject);
434
436
  }
@@ -48,13 +48,13 @@ export const getPathToIntegration = (handoff: Handoff, resolveTemplatePath: bool
48
48
  if (!handoff) {
49
49
  throw Error('Handoff not initialized');
50
50
  }
51
+ if (!handoff.force) {
52
+ const integrationPath = path.resolve(path.join(handoff.workingPath, 'integration'));
51
53
 
52
- const integrationPath = path.resolve(path.join(handoff.workingPath, 'integration'));
53
-
54
- if (fs.existsSync(integrationPath)) {
55
- return integrationPath;
54
+ if (fs.existsSync(integrationPath)) {
55
+ return integrationPath;
56
+ }
56
57
  }
57
-
58
58
  if (resolveTemplatePath) {
59
59
  return path.resolve(path.join(handoff.modulePath, 'config', 'templates', 'integration'));
60
60
  }
@@ -133,7 +133,9 @@ const buildIntegration = async (
133
133
  rootPath ??= sourcePath;
134
134
 
135
135
  const items = await fs.readdir(sourcePath);
136
+
136
137
  const components = Object.keys(documentationObject.components);
138
+ const componentsWithInstances = components.filter((component) => documentationObject.components[component].instances.length > 0);
137
139
 
138
140
  for (const item of items) {
139
141
  const sourceItemPath = path.join(sourcePath, item);
@@ -159,7 +161,16 @@ const buildIntegration = async (
159
161
  // Ensure the directory exists before writing the file
160
162
  await fs.ensureDir(path.dirname(destItemPath));
161
163
  // Write the rendered content to the destination path
162
- await fs.writeFile(destItemPath, replaceHandoffImportTokens(renderedContent, components, path.parse(destItemPath).dir, rootPath, rootReturnPath ?? '../'));
164
+ await fs.writeFile(
165
+ destItemPath,
166
+ replaceHandoffImportTokens(
167
+ renderedContent,
168
+ componentsWithInstances,
169
+ path.parse(destItemPath).dir,
170
+ rootPath,
171
+ rootReturnPath ?? '../'
172
+ )
173
+ );
163
174
  }
164
175
  }
165
176
  };
@@ -333,7 +344,13 @@ interface IntegrationTemplateContext {
333
344
  documentationObject: DocumentationObject;
334
345
  }
335
346
 
336
- const replaceHandoffImportTokens = (content: string, components: string[], currentPath: string, rootPath: string, rootReturnPath: string) => {
347
+ const replaceHandoffImportTokens = (
348
+ content: string,
349
+ components: string[],
350
+ currentPath: string,
351
+ rootPath: string,
352
+ rootReturnPath: string
353
+ ) => {
337
354
  getHandoffImportTokens(components, currentPath, rootPath, rootReturnPath).forEach(([token, imports]) => {
338
355
  content = content.replaceAll(`//<#${token}#>`, imports.map((path) => `@import '${path}';`).join(`\r\n`));
339
356
  });
@@ -95,9 +95,11 @@ export const buildClientFiles = async (handoff: Handoff): Promise<string> => {
95
95
  const compile = webpack(config);
96
96
  compile.run((err, stats) => {
97
97
  if (err) {
98
- let error = 'Errors encountered trying to build preview styles.\n';
98
+ let error = chalk.red('Errors encountered trying to build preview styles.') + '\n The integration sass expects a token that isn\'t found in your Figma component.\n';
99
99
  if (handoff.debug) {
100
- error += err.stack || err;
100
+ error += chalk.yellow('\n\n---------- Sass Build Error Trace ---------- \n') + err.stack || err;
101
+ }else{
102
+ error += 'Add the --debug flag to see the full error trace\n\n';
101
103
  }
102
104
  return reject(error);
103
105
  }
@@ -105,9 +107,11 @@ export const buildClientFiles = async (handoff: Handoff): Promise<string> => {
105
107
  if (stats) {
106
108
  if (stats.hasErrors()) {
107
109
  let buildErrors = stats.compilation.errors?.map((err) => err.message);
108
- let error = 'Errors encountered trying to build preview styles.\n';
110
+ let error = chalk.red('Errors encountered trying to build preview styles.') + '\nThe integration sass expects a token that isn\'t found in your Figma component.\n';
109
111
  if (handoff.debug) {
110
- error += buildErrors;
112
+ error += chalk.yellow('\n\n---------- Sass Build Error Trace ---------- \n') + buildErrors;
113
+ }else{
114
+ error += 'Add the --debug flag to see the full error trace\n\n';
111
115
  }
112
116
  return reject(error);
113
117
  }