@octaviaflow/feature-flags 1.0.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 ADDED
@@ -0,0 +1,116 @@
1
+ # @octaviaflow/feature-flags
2
+
3
+ > Build with feature flags in Carbon
4
+
5
+ ## Getting started
6
+
7
+ To install `@octaviaflow/feature-flags` in your project, you will need to run the
8
+ following command using [npm](https://www.npmjs.com/):
9
+
10
+ ```bash
11
+ npm install -S @octaviaflow/feature-flags
12
+ ```
13
+
14
+ If you prefer [Yarn](https://yarnpkg.com/en/), use the following command
15
+ instead:
16
+
17
+ ```bash
18
+ yarn add @octaviaflow/feature-flags
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ The `@octaviaflow/feature-flags` provides a runtime-based feature flag system that
24
+ you can use to enable or disable experimental features from Carbon or in your
25
+ own code.
26
+
27
+ To check if a feature flag is enabled, you can use the `enabled` function in
28
+ JavaScript:
29
+
30
+ ```js
31
+ import { enabled } from '@octaviaflow/feature-flags';
32
+
33
+ enabled('feature-flag-name');
34
+ ```
35
+
36
+ In Sass, you would use the `enabled` function or mixin:
37
+
38
+ ```scss
39
+ @use '@octaviaflow/feature-flags';
40
+
41
+ // Return true if the flag is enabled
42
+ @if feature-flags.enabled('feature-flag-name') {
43
+ //
44
+ }
45
+
46
+ @include enabled('feature-flag-name') {
47
+ // only include contents if the flag is enabled
48
+ }
49
+ ```
50
+
51
+ ### Managing feature flags
52
+
53
+ You can change whether a feature flag is enabled. In JavaScript, you can use the
54
+ `enable`, `disable`, and `merge` functions to accomplish this.
55
+
56
+ ```js
57
+ import { enable, disable, merge } from '@octaviaflow/feature-flags';
58
+
59
+ // Enable `feature-flag-a`
60
+ enable('feature-flag-a');
61
+
62
+ // Disable `feature-flag-a`
63
+ disable('feature-flag-a');
64
+
65
+ // Set a variety of feature flags to a specific value
66
+ merge({
67
+ 'feature-flag-a': true,
68
+ 'feature-flag-b': false,
69
+ 'feature-flag-c': true,
70
+ });
71
+ ```
72
+
73
+ In Sass, you can configure whether a feature flag is enabled when you include
74
+ the module or by using `enable`, `disable`, and `merge`.
75
+
76
+ ```scss
77
+ @use '@octaviaflow/feature-flags' with (
78
+ $feature-flags: (
79
+ 'feature-flag-a': false,
80
+ 'feature-flag-b': true,
81
+ )
82
+ );
83
+
84
+ // Enable `feature-flag-a`
85
+ @include feature-flags.enable('feature-flag-a');
86
+
87
+ // Disable `feature-flag-b`
88
+ @include feature-flags.disable('feature-flag-b');
89
+
90
+ // Set a variety of feature flags to a specific value
91
+ @include feature-flags.merge(
92
+ (
93
+ 'feature-flag-a': true,
94
+ 'feature-flag-b': true,
95
+ )
96
+ );
97
+ ```
98
+
99
+ ## 🙌 Contributing
100
+
101
+ We're always looking for contributors to help us fix bugs, build new features,
102
+ or help us improve the project documentation. If you're interested, definitely
103
+ check out our [Contributing Guide](/.github/CONTRIBUTING.md)! 👀
104
+
105
+ ## 📝 License
106
+
107
+ Licensed under the [Apache 2.0 License](/LICENSE).
108
+
109
+ ## <picture><source height="20" width="20" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ibm-telemetry/telemetry-js/main/docs/images/ibm-telemetry-dark.svg"><source height="20" width="20" media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ibm-telemetry/telemetry-js/main/docs/images/ibm-telemetry-light.svg"><img height="20" width="20" alt="IBM Telemetry" src="https://raw.githubusercontent.com/ibm-telemetry/telemetry-js/main/docs/images/ibm-telemetry-light.svg"></picture> IBM Telemetry
110
+
111
+ This package uses IBM Telemetry to collect de-identified and anonymized metrics
112
+ data. By installing this package as a dependency you are agreeing to telemetry
113
+ collection. To opt out, see
114
+ [Opting out of IBM Telemetry data collection](https://github.com/ibm-telemetry/telemetry-js/tree/main#opting-out-of-ibm-telemetry-data-collection).
115
+ For more information on the data being collected, please see the
116
+ [IBM Telemetry documentation](https://github.com/ibm-telemetry/telemetry-js/tree/main#ibm-telemetry-collection-basics).
package/es/index.js ADDED
@@ -0,0 +1,432 @@
1
+
2
+
3
+ var enabled$1 = {};
4
+ try {
5
+ if (process.env.CARBON_ENABLE_CSS_CUSTOM_PROPERTIES) {
6
+ if (process.env.CARBON_ENABLE_CSS_CUSTOM_PROPERTIES === 'true') {
7
+ enabled$1.enableCssCustomProperties = true;
8
+ } else {
9
+ enabled$1.enableCssCustomProperties = false;
10
+ }
11
+ } else {
12
+ enabled$1.enableCssCustomProperties = false;
13
+ }
14
+ if (process.env.CARBON_ENABLE_CSS_GRID) {
15
+ if (process.env.CARBON_ENABLE_CSS_GRID === 'true') {
16
+ enabled$1.enableCssGrid = true;
17
+ } else {
18
+ enabled$1.enableCssGrid = false;
19
+ }
20
+ } else {
21
+ enabled$1.enableCssGrid = false;
22
+ }
23
+ if (process.env.CARBON_ENABLE_V11_RELEASE) {
24
+ if (process.env.CARBON_ENABLE_V11_RELEASE === 'true') {
25
+ enabled$1.enableV11Release = true;
26
+ } else {
27
+ enabled$1.enableV11Release = false;
28
+ }
29
+ } else {
30
+ enabled$1.enableV11Release = true;
31
+ }
32
+ if (process.env.CARBON_ENABLE_EXPERIMENTAL_TILE_CONTRAST) {
33
+ if (process.env.CARBON_ENABLE_EXPERIMENTAL_TILE_CONTRAST === 'true') {
34
+ enabled$1.enableExperimentalTileContrast = true;
35
+ } else {
36
+ enabled$1.enableExperimentalTileContrast = false;
37
+ }
38
+ } else {
39
+ enabled$1.enableExperimentalTileContrast = false;
40
+ }
41
+ if (process.env.CARBON_ENABLE_V12_TILE_DEFAULT_ICONS) {
42
+ if (process.env.CARBON_ENABLE_V12_TILE_DEFAULT_ICONS === 'true') {
43
+ enabled$1.enableV12TileDefaultIcons = true;
44
+ } else {
45
+ enabled$1.enableV12TileDefaultIcons = false;
46
+ }
47
+ } else {
48
+ enabled$1.enableV12TileDefaultIcons = false;
49
+ }
50
+ if (process.env.CARBON_ENABLE_V12_TILE_RADIO_ICONS) {
51
+ if (process.env.CARBON_ENABLE_V12_TILE_RADIO_ICONS === 'true') {
52
+ enabled$1.enableV12TileRadioIcons = true;
53
+ } else {
54
+ enabled$1.enableV12TileRadioIcons = false;
55
+ }
56
+ } else {
57
+ enabled$1.enableV12TileRadioIcons = false;
58
+ }
59
+ if (process.env.CARBON_ENABLE_V12_OVERFLOWMENU) {
60
+ if (process.env.CARBON_ENABLE_V12_OVERFLOWMENU === 'true') {
61
+ enabled$1.enableV12Overflowmenu = true;
62
+ } else {
63
+ enabled$1.enableV12Overflowmenu = false;
64
+ }
65
+ } else {
66
+ enabled$1.enableV12Overflowmenu = false;
67
+ }
68
+ if (process.env.CARBON_ENABLE_TREEVIEW_CONTROLLABLE) {
69
+ if (process.env.CARBON_ENABLE_TREEVIEW_CONTROLLABLE === 'true') {
70
+ enabled$1.enableTreeviewControllable = true;
71
+ } else {
72
+ enabled$1.enableTreeviewControllable = false;
73
+ }
74
+ } else {
75
+ enabled$1.enableTreeviewControllable = false;
76
+ }
77
+ if (process.env.CARBON_ENABLE_V12_STRUCTURED_LIST_VISIBLE_ICONS) {
78
+ if (process.env.CARBON_ENABLE_V12_STRUCTURED_LIST_VISIBLE_ICONS === 'true') {
79
+ enabled$1.enableV12StructuredListVisibleIcons = true;
80
+ } else {
81
+ enabled$1.enableV12StructuredListVisibleIcons = false;
82
+ }
83
+ } else {
84
+ enabled$1.enableV12StructuredListVisibleIcons = false;
85
+ }
86
+ if (process.env.CARBON_ENABLE_EXPERIMENTAL_FOCUS_WRAP_WITHOUT_SENTINELS) {
87
+ if (process.env.CARBON_ENABLE_EXPERIMENTAL_FOCUS_WRAP_WITHOUT_SENTINELS === 'true') {
88
+ enabled$1.enableExperimentalFocusWrapWithoutSentinels = true;
89
+ } else {
90
+ enabled$1.enableExperimentalFocusWrapWithoutSentinels = false;
91
+ }
92
+ } else {
93
+ enabled$1.enableExperimentalFocusWrapWithoutSentinels = false;
94
+ }
95
+ if (process.env.CARBON_ENABLE_V12_DYNAMIC_FLOATING_STYLES) {
96
+ if (process.env.CARBON_ENABLE_V12_DYNAMIC_FLOATING_STYLES === 'true') {
97
+ enabled$1.enableV12DynamicFloatingStyles = true;
98
+ } else {
99
+ enabled$1.enableV12DynamicFloatingStyles = false;
100
+ }
101
+ } else {
102
+ enabled$1.enableV12DynamicFloatingStyles = false;
103
+ }
104
+ } catch (error) {
105
+ enabled$1.enableCssCustomProperties = false;
106
+ enabled$1.enableCssGrid = false;
107
+ enabled$1.enableV11Release = true;
108
+ enabled$1.enableExperimentalTileContrast = false;
109
+ enabled$1.enableV12TileDefaultIcons = false;
110
+ enabled$1.enableV12TileRadioIcons = false;
111
+ enabled$1.enableV12Overflowmenu = false;
112
+ enabled$1.enableTreeviewControllable = false;
113
+ enabled$1.enableV12StructuredListVisibleIcons = false;
114
+ enabled$1.enableExperimentalFocusWrapWithoutSentinels = false;
115
+ enabled$1.enableV12DynamicFloatingStyles = false;
116
+ }
117
+ var featureFlagInfo = [{
118
+ name: "enable-css-custom-properties",
119
+ description: "Describe what the flag does",
120
+ enabled: enabled$1.enableCssCustomProperties
121
+ }, {
122
+ name: "enable-css-grid",
123
+ description: "Enable CSS Grid Layout in the Grid and Column React components\n",
124
+ enabled: enabled$1.enableCssGrid
125
+ }, {
126
+ name: "enable-v11-release",
127
+ description: "Enable the features and functionality for the v11 Release\n",
128
+ enabled: enabled$1.enableV11Release
129
+ }, {
130
+ name: "enable-experimental-tile-contrast",
131
+ description: "Enable the experimental tile improved contrast styles\n",
132
+ enabled: enabled$1.enableExperimentalTileContrast
133
+ }, {
134
+ name: "enable-v12-tile-default-icons",
135
+ description: "Enable rendering of default icons in the tile components\n",
136
+ enabled: enabled$1.enableV12TileDefaultIcons
137
+ }, {
138
+ name: "enable-v12-tile-radio-icons",
139
+ description: "Enable rendering of radio icons in the RadioTile component\n",
140
+ enabled: enabled$1.enableV12TileRadioIcons
141
+ }, {
142
+ name: "enable-v12-overflowmenu",
143
+ description: "Enable the use of the v12 OverflowMenu leveraging the Menu subcomponents\n",
144
+ enabled: enabled$1.enableV12Overflowmenu
145
+ }, {
146
+ name: "enable-treeview-controllable",
147
+ description: "Enable the new TreeView controllable API\n",
148
+ enabled: enabled$1.enableTreeviewControllable
149
+ }, {
150
+ name: "enable-v12-structured-list-visible-icons",
151
+ description: "Enable rendering of radio icons in the StructuredList component\n",
152
+ enabled: enabled$1.enableV12StructuredListVisibleIcons
153
+ }, {
154
+ name: "enable-experimental-focus-wrap-without-sentinels",
155
+ description: "Enable the new focus wrap behavior that doesn't use sentinel nodes\n",
156
+ enabled: enabled$1.enableExperimentalFocusWrapWithoutSentinels
157
+ }, {
158
+ name: "enable-v12-dynamic-floating-styles",
159
+ description: "Enable dynamic setting of floating styles for components like Popover, Tooltip, etc.\n",
160
+ enabled: enabled$1.enableV12DynamicFloatingStyles
161
+ }];
162
+
163
+ function _arrayLikeToArray(r, a) {
164
+ (null == a || a > r.length) && (a = r.length);
165
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
166
+ return n;
167
+ }
168
+ function _arrayWithHoles(r) {
169
+ if (Array.isArray(r)) return r;
170
+ }
171
+ function _classCallCheck(a, n) {
172
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
173
+ }
174
+ function _defineProperties(e, r) {
175
+ for (var t = 0; t < r.length; t++) {
176
+ var o = r[t];
177
+ o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
178
+ }
179
+ }
180
+ function _createClass(e, r, t) {
181
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
182
+ writable: !1
183
+ }), e;
184
+ }
185
+ function _createForOfIteratorHelper(r, e) {
186
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
187
+ if (!t) {
188
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
189
+ t && (r = t);
190
+ var n = 0,
191
+ F = function () {};
192
+ return {
193
+ s: F,
194
+ n: function () {
195
+ return n >= r.length ? {
196
+ done: !0
197
+ } : {
198
+ done: !1,
199
+ value: r[n++]
200
+ };
201
+ },
202
+ e: function (r) {
203
+ throw r;
204
+ },
205
+ f: F
206
+ };
207
+ }
208
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
209
+ }
210
+ var o,
211
+ a = !0,
212
+ u = !1;
213
+ return {
214
+ s: function () {
215
+ t = t.call(r);
216
+ },
217
+ n: function () {
218
+ var r = t.next();
219
+ return a = r.done, r;
220
+ },
221
+ e: function (r) {
222
+ u = !0, o = r;
223
+ },
224
+ f: function () {
225
+ try {
226
+ a || null == t.return || t.return();
227
+ } finally {
228
+ if (u) throw o;
229
+ }
230
+ }
231
+ };
232
+ }
233
+ function _iterableToArrayLimit(r, l) {
234
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
235
+ if (null != t) {
236
+ var e,
237
+ n,
238
+ i,
239
+ u,
240
+ a = [],
241
+ f = !0,
242
+ o = !1;
243
+ try {
244
+ if (i = (t = t.call(r)).next, 0 === l) {
245
+ if (Object(t) !== t) return;
246
+ f = !1;
247
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
248
+ } catch (r) {
249
+ o = !0, n = r;
250
+ } finally {
251
+ try {
252
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
253
+ } finally {
254
+ if (o) throw n;
255
+ }
256
+ }
257
+ return a;
258
+ }
259
+ }
260
+ function _nonIterableRest() {
261
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
262
+ }
263
+ function _slicedToArray(r, e) {
264
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
265
+ }
266
+ function _toPrimitive(t, r) {
267
+ if ("object" != typeof t || !t) return t;
268
+ var e = t[Symbol.toPrimitive];
269
+ if (void 0 !== e) {
270
+ var i = e.call(t, r || "default");
271
+ if ("object" != typeof i) return i;
272
+ throw new TypeError("@@toPrimitive must return a primitive value.");
273
+ }
274
+ return ("string" === r ? String : Number)(t);
275
+ }
276
+ function _toPropertyKey(t) {
277
+ var i = _toPrimitive(t, "string");
278
+ return "symbol" == typeof i ? i : i + "";
279
+ }
280
+ function _unsupportedIterableToArray(r, a) {
281
+ if (r) {
282
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
283
+ var t = {}.toString.call(r).slice(8, -1);
284
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Copyright OctaviaFlow. 2025
290
+ *
291
+ * This source code is licensed under the Apache-2.0 license found in the
292
+ * LICENSE file in the root directory of this source tree.
293
+ */
294
+
295
+ var FeatureFlagScope = /*#__PURE__*/function () {
296
+ function FeatureFlagScope(flags) {
297
+ var _this = this;
298
+ _classCallCheck(this, FeatureFlagScope);
299
+ this.flags = new Map();
300
+ if (flags) {
301
+ Object.keys(flags).forEach(function (key) {
302
+ _this.flags.set(key, flags[key]);
303
+ });
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Check to see if a flag exists
309
+ * @param {string} name
310
+ */
311
+ return _createClass(FeatureFlagScope, [{
312
+ key: "checkForFlag",
313
+ value: function checkForFlag(name) {
314
+ if (!this.flags.has(name)) {
315
+ throw new Error("Unable to find a feature flag with the name: `".concat(name, "`"));
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Add a feature flag
321
+ * @param {string} name
322
+ * @param {boolean} enabled
323
+ */
324
+ }, {
325
+ key: "add",
326
+ value: function add(name, enabled) {
327
+ if (this.flags.has(name)) {
328
+ throw new Error("The feature flag: ".concat(name, " already exists"));
329
+ }
330
+ this.flags.set(name, enabled);
331
+ }
332
+
333
+ /**
334
+ * Enable a feature flag
335
+ * @param {string} name
336
+ */
337
+ }, {
338
+ key: "enable",
339
+ value: function enable(name) {
340
+ this.checkForFlag(name);
341
+ this.flags.set(name, true);
342
+ }
343
+
344
+ /**
345
+ * Disable a feature flag
346
+ * @param {string} name
347
+ */
348
+ }, {
349
+ key: "disable",
350
+ value: function disable(name) {
351
+ this.checkForFlag(name);
352
+ this.flags.set(name, false);
353
+ }
354
+
355
+ /**
356
+ * Merge the given feature flags with the current set of feature flags.
357
+ * Duplicate keys will be set to the value in the given feature flags.
358
+ * @param {object} flags
359
+ */
360
+ }, {
361
+ key: "merge",
362
+ value: function merge(flags) {
363
+ var _this2 = this;
364
+ Object.keys(flags).forEach(function (key) {
365
+ _this2.flags.set(key, flags[key]);
366
+ });
367
+ }
368
+
369
+ /**
370
+ * @param {FeatureFlagScope} scope
371
+ */
372
+ }, {
373
+ key: "mergeWithScope",
374
+ value: function mergeWithScope(scope) {
375
+ var _iterator = _createForOfIteratorHelper(scope.flags),
376
+ _step;
377
+ try {
378
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
379
+ var _step$value = _slicedToArray(_step.value, 2),
380
+ key = _step$value[0],
381
+ value = _step$value[1];
382
+ if (this.flags.has(key)) {
383
+ continue;
384
+ }
385
+ this.flags.set(key, value);
386
+ }
387
+ } catch (err) {
388
+ _iterator.e(err);
389
+ } finally {
390
+ _iterator.f();
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Check if a feature flag is enabled
396
+ * @param {string} name
397
+ * @returns {boolean}
398
+ */
399
+ }, {
400
+ key: "enabled",
401
+ value: function enabled(name) {
402
+ this.checkForFlag(name);
403
+ return this.flags.get(name);
404
+ }
405
+ }]);
406
+ }();
407
+
408
+ var FeatureFlags = createScope();
409
+ for (var i = 0; i < featureFlagInfo.length; i++) {
410
+ var featureFlag = featureFlagInfo[i];
411
+ FeatureFlags.add(featureFlag.name, featureFlag.enabled);
412
+ }
413
+ function createScope(flags) {
414
+ return new FeatureFlagScope(flags);
415
+ }
416
+ function add() {
417
+ return FeatureFlags.add.apply(FeatureFlags, arguments);
418
+ }
419
+ function enable() {
420
+ return FeatureFlags.enable.apply(FeatureFlags, arguments);
421
+ }
422
+ function disable() {
423
+ return FeatureFlags.disable.apply(FeatureFlags, arguments);
424
+ }
425
+ function enabled() {
426
+ return FeatureFlags.enabled.apply(FeatureFlags, arguments);
427
+ }
428
+ function merge() {
429
+ return FeatureFlags.merge.apply(FeatureFlags, arguments);
430
+ }
431
+
432
+ export { FeatureFlags, add, createScope, disable, enable, enabled, merge };
package/index.scss ADDED
@@ -0,0 +1,64 @@
1
+ //
2
+ // Copyright IBM Corp. 2015, 2023
3
+ //
4
+ // This source code is licensed under the Apache-2.0 license found in the
5
+ // LICENSE file in the root directory of this source tree.
6
+ //
7
+
8
+ @use 'sass:map';
9
+ @use 'scss/generated/feature-flags';
10
+
11
+ $feature-flags: () !default;
12
+ $feature-flags: map.merge(
13
+ feature-flags.$generated-feature-flags,
14
+ $feature-flags
15
+ );
16
+
17
+ @function check-for-flag($name) {
18
+ @if map.has-key($feature-flags, $name) == true {
19
+ @return true;
20
+ }
21
+ @error 'Unable to find a feature flag named: #{$name}';
22
+ }
23
+
24
+ @mixin add($name, $enabled: false) {
25
+ @if map.has-key($feature-flags, $name) == true {
26
+ @error 'A feature flag named #{$name} already exists';
27
+ }
28
+
29
+ $feature-flags: map.set($feature-flags, $name, $enabled) !global;
30
+ }
31
+
32
+ @mixin enable($name) {
33
+ @if check-for-flag($name) == true {
34
+ $feature-flags: map.set($feature-flags, $name, true) !global;
35
+ }
36
+ }
37
+
38
+ @mixin disable($name) {
39
+ @if check-for-flag($name) == true {
40
+ $feature-flags: map.set($feature-flags, $name, false) !global;
41
+ }
42
+ }
43
+
44
+ @mixin merge($flags) {
45
+ $feature-flags: map.merge($feature-flags, $flags) !global;
46
+ }
47
+
48
+ /// Check if a feature flag is enabled
49
+ /// @param {String} $name
50
+ /// @returns {Boolean}
51
+ @function enabled($name) {
52
+ @if check-for-flag($name) == true {
53
+ @return map.get($feature-flags, $name);
54
+ }
55
+ }
56
+
57
+ /// Emit the content of the mixin if the feature flag is enabled
58
+ /// @param {String} $name
59
+ /// @content
60
+ @mixin enabled($name) {
61
+ @if enabled($name) {
62
+ @content;
63
+ }
64
+ }
package/lib/index.js ADDED
@@ -0,0 +1,442 @@
1
+
2
+
3
+ 'use strict';
4
+
5
+ Object.defineProperty(exports, '__esModule', { value: true });
6
+
7
+ var enabled$1 = {};
8
+ try {
9
+ if (process.env.CARBON_ENABLE_CSS_CUSTOM_PROPERTIES) {
10
+ if (process.env.CARBON_ENABLE_CSS_CUSTOM_PROPERTIES === 'true') {
11
+ enabled$1.enableCssCustomProperties = true;
12
+ } else {
13
+ enabled$1.enableCssCustomProperties = false;
14
+ }
15
+ } else {
16
+ enabled$1.enableCssCustomProperties = false;
17
+ }
18
+ if (process.env.CARBON_ENABLE_CSS_GRID) {
19
+ if (process.env.CARBON_ENABLE_CSS_GRID === 'true') {
20
+ enabled$1.enableCssGrid = true;
21
+ } else {
22
+ enabled$1.enableCssGrid = false;
23
+ }
24
+ } else {
25
+ enabled$1.enableCssGrid = false;
26
+ }
27
+ if (process.env.CARBON_ENABLE_V11_RELEASE) {
28
+ if (process.env.CARBON_ENABLE_V11_RELEASE === 'true') {
29
+ enabled$1.enableV11Release = true;
30
+ } else {
31
+ enabled$1.enableV11Release = false;
32
+ }
33
+ } else {
34
+ enabled$1.enableV11Release = true;
35
+ }
36
+ if (process.env.CARBON_ENABLE_EXPERIMENTAL_TILE_CONTRAST) {
37
+ if (process.env.CARBON_ENABLE_EXPERIMENTAL_TILE_CONTRAST === 'true') {
38
+ enabled$1.enableExperimentalTileContrast = true;
39
+ } else {
40
+ enabled$1.enableExperimentalTileContrast = false;
41
+ }
42
+ } else {
43
+ enabled$1.enableExperimentalTileContrast = false;
44
+ }
45
+ if (process.env.CARBON_ENABLE_V12_TILE_DEFAULT_ICONS) {
46
+ if (process.env.CARBON_ENABLE_V12_TILE_DEFAULT_ICONS === 'true') {
47
+ enabled$1.enableV12TileDefaultIcons = true;
48
+ } else {
49
+ enabled$1.enableV12TileDefaultIcons = false;
50
+ }
51
+ } else {
52
+ enabled$1.enableV12TileDefaultIcons = false;
53
+ }
54
+ if (process.env.CARBON_ENABLE_V12_TILE_RADIO_ICONS) {
55
+ if (process.env.CARBON_ENABLE_V12_TILE_RADIO_ICONS === 'true') {
56
+ enabled$1.enableV12TileRadioIcons = true;
57
+ } else {
58
+ enabled$1.enableV12TileRadioIcons = false;
59
+ }
60
+ } else {
61
+ enabled$1.enableV12TileRadioIcons = false;
62
+ }
63
+ if (process.env.CARBON_ENABLE_V12_OVERFLOWMENU) {
64
+ if (process.env.CARBON_ENABLE_V12_OVERFLOWMENU === 'true') {
65
+ enabled$1.enableV12Overflowmenu = true;
66
+ } else {
67
+ enabled$1.enableV12Overflowmenu = false;
68
+ }
69
+ } else {
70
+ enabled$1.enableV12Overflowmenu = false;
71
+ }
72
+ if (process.env.CARBON_ENABLE_TREEVIEW_CONTROLLABLE) {
73
+ if (process.env.CARBON_ENABLE_TREEVIEW_CONTROLLABLE === 'true') {
74
+ enabled$1.enableTreeviewControllable = true;
75
+ } else {
76
+ enabled$1.enableTreeviewControllable = false;
77
+ }
78
+ } else {
79
+ enabled$1.enableTreeviewControllable = false;
80
+ }
81
+ if (process.env.CARBON_ENABLE_V12_STRUCTURED_LIST_VISIBLE_ICONS) {
82
+ if (process.env.CARBON_ENABLE_V12_STRUCTURED_LIST_VISIBLE_ICONS === 'true') {
83
+ enabled$1.enableV12StructuredListVisibleIcons = true;
84
+ } else {
85
+ enabled$1.enableV12StructuredListVisibleIcons = false;
86
+ }
87
+ } else {
88
+ enabled$1.enableV12StructuredListVisibleIcons = false;
89
+ }
90
+ if (process.env.CARBON_ENABLE_EXPERIMENTAL_FOCUS_WRAP_WITHOUT_SENTINELS) {
91
+ if (process.env.CARBON_ENABLE_EXPERIMENTAL_FOCUS_WRAP_WITHOUT_SENTINELS === 'true') {
92
+ enabled$1.enableExperimentalFocusWrapWithoutSentinels = true;
93
+ } else {
94
+ enabled$1.enableExperimentalFocusWrapWithoutSentinels = false;
95
+ }
96
+ } else {
97
+ enabled$1.enableExperimentalFocusWrapWithoutSentinels = false;
98
+ }
99
+ if (process.env.CARBON_ENABLE_V12_DYNAMIC_FLOATING_STYLES) {
100
+ if (process.env.CARBON_ENABLE_V12_DYNAMIC_FLOATING_STYLES === 'true') {
101
+ enabled$1.enableV12DynamicFloatingStyles = true;
102
+ } else {
103
+ enabled$1.enableV12DynamicFloatingStyles = false;
104
+ }
105
+ } else {
106
+ enabled$1.enableV12DynamicFloatingStyles = false;
107
+ }
108
+ } catch (error) {
109
+ enabled$1.enableCssCustomProperties = false;
110
+ enabled$1.enableCssGrid = false;
111
+ enabled$1.enableV11Release = true;
112
+ enabled$1.enableExperimentalTileContrast = false;
113
+ enabled$1.enableV12TileDefaultIcons = false;
114
+ enabled$1.enableV12TileRadioIcons = false;
115
+ enabled$1.enableV12Overflowmenu = false;
116
+ enabled$1.enableTreeviewControllable = false;
117
+ enabled$1.enableV12StructuredListVisibleIcons = false;
118
+ enabled$1.enableExperimentalFocusWrapWithoutSentinels = false;
119
+ enabled$1.enableV12DynamicFloatingStyles = false;
120
+ }
121
+ var featureFlagInfo = [{
122
+ name: "enable-css-custom-properties",
123
+ description: "Describe what the flag does",
124
+ enabled: enabled$1.enableCssCustomProperties
125
+ }, {
126
+ name: "enable-css-grid",
127
+ description: "Enable CSS Grid Layout in the Grid and Column React components\n",
128
+ enabled: enabled$1.enableCssGrid
129
+ }, {
130
+ name: "enable-v11-release",
131
+ description: "Enable the features and functionality for the v11 Release\n",
132
+ enabled: enabled$1.enableV11Release
133
+ }, {
134
+ name: "enable-experimental-tile-contrast",
135
+ description: "Enable the experimental tile improved contrast styles\n",
136
+ enabled: enabled$1.enableExperimentalTileContrast
137
+ }, {
138
+ name: "enable-v12-tile-default-icons",
139
+ description: "Enable rendering of default icons in the tile components\n",
140
+ enabled: enabled$1.enableV12TileDefaultIcons
141
+ }, {
142
+ name: "enable-v12-tile-radio-icons",
143
+ description: "Enable rendering of radio icons in the RadioTile component\n",
144
+ enabled: enabled$1.enableV12TileRadioIcons
145
+ }, {
146
+ name: "enable-v12-overflowmenu",
147
+ description: "Enable the use of the v12 OverflowMenu leveraging the Menu subcomponents\n",
148
+ enabled: enabled$1.enableV12Overflowmenu
149
+ }, {
150
+ name: "enable-treeview-controllable",
151
+ description: "Enable the new TreeView controllable API\n",
152
+ enabled: enabled$1.enableTreeviewControllable
153
+ }, {
154
+ name: "enable-v12-structured-list-visible-icons",
155
+ description: "Enable rendering of radio icons in the StructuredList component\n",
156
+ enabled: enabled$1.enableV12StructuredListVisibleIcons
157
+ }, {
158
+ name: "enable-experimental-focus-wrap-without-sentinels",
159
+ description: "Enable the new focus wrap behavior that doesn't use sentinel nodes\n",
160
+ enabled: enabled$1.enableExperimentalFocusWrapWithoutSentinels
161
+ }, {
162
+ name: "enable-v12-dynamic-floating-styles",
163
+ description: "Enable dynamic setting of floating styles for components like Popover, Tooltip, etc.\n",
164
+ enabled: enabled$1.enableV12DynamicFloatingStyles
165
+ }];
166
+
167
+ function _arrayLikeToArray(r, a) {
168
+ (null == a || a > r.length) && (a = r.length);
169
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
170
+ return n;
171
+ }
172
+ function _arrayWithHoles(r) {
173
+ if (Array.isArray(r)) return r;
174
+ }
175
+ function _classCallCheck(a, n) {
176
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
177
+ }
178
+ function _defineProperties(e, r) {
179
+ for (var t = 0; t < r.length; t++) {
180
+ var o = r[t];
181
+ o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
182
+ }
183
+ }
184
+ function _createClass(e, r, t) {
185
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
186
+ writable: !1
187
+ }), e;
188
+ }
189
+ function _createForOfIteratorHelper(r, e) {
190
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
191
+ if (!t) {
192
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
193
+ t && (r = t);
194
+ var n = 0,
195
+ F = function () {};
196
+ return {
197
+ s: F,
198
+ n: function () {
199
+ return n >= r.length ? {
200
+ done: !0
201
+ } : {
202
+ done: !1,
203
+ value: r[n++]
204
+ };
205
+ },
206
+ e: function (r) {
207
+ throw r;
208
+ },
209
+ f: F
210
+ };
211
+ }
212
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
213
+ }
214
+ var o,
215
+ a = !0,
216
+ u = !1;
217
+ return {
218
+ s: function () {
219
+ t = t.call(r);
220
+ },
221
+ n: function () {
222
+ var r = t.next();
223
+ return a = r.done, r;
224
+ },
225
+ e: function (r) {
226
+ u = !0, o = r;
227
+ },
228
+ f: function () {
229
+ try {
230
+ a || null == t.return || t.return();
231
+ } finally {
232
+ if (u) throw o;
233
+ }
234
+ }
235
+ };
236
+ }
237
+ function _iterableToArrayLimit(r, l) {
238
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
239
+ if (null != t) {
240
+ var e,
241
+ n,
242
+ i,
243
+ u,
244
+ a = [],
245
+ f = !0,
246
+ o = !1;
247
+ try {
248
+ if (i = (t = t.call(r)).next, 0 === l) {
249
+ if (Object(t) !== t) return;
250
+ f = !1;
251
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
252
+ } catch (r) {
253
+ o = !0, n = r;
254
+ } finally {
255
+ try {
256
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
257
+ } finally {
258
+ if (o) throw n;
259
+ }
260
+ }
261
+ return a;
262
+ }
263
+ }
264
+ function _nonIterableRest() {
265
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
266
+ }
267
+ function _slicedToArray(r, e) {
268
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
269
+ }
270
+ function _toPrimitive(t, r) {
271
+ if ("object" != typeof t || !t) return t;
272
+ var e = t[Symbol.toPrimitive];
273
+ if (void 0 !== e) {
274
+ var i = e.call(t, r || "default");
275
+ if ("object" != typeof i) return i;
276
+ throw new TypeError("@@toPrimitive must return a primitive value.");
277
+ }
278
+ return ("string" === r ? String : Number)(t);
279
+ }
280
+ function _toPropertyKey(t) {
281
+ var i = _toPrimitive(t, "string");
282
+ return "symbol" == typeof i ? i : i + "";
283
+ }
284
+ function _unsupportedIterableToArray(r, a) {
285
+ if (r) {
286
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
287
+ var t = {}.toString.call(r).slice(8, -1);
288
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Copyright OctaviaFlow. 2025
294
+ *
295
+ * This source code is licensed under the Apache-2.0 license found in the
296
+ * LICENSE file in the root directory of this source tree.
297
+ */
298
+
299
+ var FeatureFlagScope = /*#__PURE__*/function () {
300
+ function FeatureFlagScope(flags) {
301
+ var _this = this;
302
+ _classCallCheck(this, FeatureFlagScope);
303
+ this.flags = new Map();
304
+ if (flags) {
305
+ Object.keys(flags).forEach(function (key) {
306
+ _this.flags.set(key, flags[key]);
307
+ });
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Check to see if a flag exists
313
+ * @param {string} name
314
+ */
315
+ return _createClass(FeatureFlagScope, [{
316
+ key: "checkForFlag",
317
+ value: function checkForFlag(name) {
318
+ if (!this.flags.has(name)) {
319
+ throw new Error("Unable to find a feature flag with the name: `".concat(name, "`"));
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Add a feature flag
325
+ * @param {string} name
326
+ * @param {boolean} enabled
327
+ */
328
+ }, {
329
+ key: "add",
330
+ value: function add(name, enabled) {
331
+ if (this.flags.has(name)) {
332
+ throw new Error("The feature flag: ".concat(name, " already exists"));
333
+ }
334
+ this.flags.set(name, enabled);
335
+ }
336
+
337
+ /**
338
+ * Enable a feature flag
339
+ * @param {string} name
340
+ */
341
+ }, {
342
+ key: "enable",
343
+ value: function enable(name) {
344
+ this.checkForFlag(name);
345
+ this.flags.set(name, true);
346
+ }
347
+
348
+ /**
349
+ * Disable a feature flag
350
+ * @param {string} name
351
+ */
352
+ }, {
353
+ key: "disable",
354
+ value: function disable(name) {
355
+ this.checkForFlag(name);
356
+ this.flags.set(name, false);
357
+ }
358
+
359
+ /**
360
+ * Merge the given feature flags with the current set of feature flags.
361
+ * Duplicate keys will be set to the value in the given feature flags.
362
+ * @param {object} flags
363
+ */
364
+ }, {
365
+ key: "merge",
366
+ value: function merge(flags) {
367
+ var _this2 = this;
368
+ Object.keys(flags).forEach(function (key) {
369
+ _this2.flags.set(key, flags[key]);
370
+ });
371
+ }
372
+
373
+ /**
374
+ * @param {FeatureFlagScope} scope
375
+ */
376
+ }, {
377
+ key: "mergeWithScope",
378
+ value: function mergeWithScope(scope) {
379
+ var _iterator = _createForOfIteratorHelper(scope.flags),
380
+ _step;
381
+ try {
382
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
383
+ var _step$value = _slicedToArray(_step.value, 2),
384
+ key = _step$value[0],
385
+ value = _step$value[1];
386
+ if (this.flags.has(key)) {
387
+ continue;
388
+ }
389
+ this.flags.set(key, value);
390
+ }
391
+ } catch (err) {
392
+ _iterator.e(err);
393
+ } finally {
394
+ _iterator.f();
395
+ }
396
+ }
397
+
398
+ /**
399
+ * Check if a feature flag is enabled
400
+ * @param {string} name
401
+ * @returns {boolean}
402
+ */
403
+ }, {
404
+ key: "enabled",
405
+ value: function enabled(name) {
406
+ this.checkForFlag(name);
407
+ return this.flags.get(name);
408
+ }
409
+ }]);
410
+ }();
411
+
412
+ var FeatureFlags = createScope();
413
+ for (var i = 0; i < featureFlagInfo.length; i++) {
414
+ var featureFlag = featureFlagInfo[i];
415
+ FeatureFlags.add(featureFlag.name, featureFlag.enabled);
416
+ }
417
+ function createScope(flags) {
418
+ return new FeatureFlagScope(flags);
419
+ }
420
+ function add() {
421
+ return FeatureFlags.add.apply(FeatureFlags, arguments);
422
+ }
423
+ function enable() {
424
+ return FeatureFlags.enable.apply(FeatureFlags, arguments);
425
+ }
426
+ function disable() {
427
+ return FeatureFlags.disable.apply(FeatureFlags, arguments);
428
+ }
429
+ function enabled() {
430
+ return FeatureFlags.enabled.apply(FeatureFlags, arguments);
431
+ }
432
+ function merge() {
433
+ return FeatureFlags.merge.apply(FeatureFlags, arguments);
434
+ }
435
+
436
+ exports.FeatureFlags = FeatureFlags;
437
+ exports.add = add;
438
+ exports.createScope = createScope;
439
+ exports.disable = disable;
440
+ exports.enable = enable;
441
+ exports.enabled = enabled;
442
+ exports.merge = merge;
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@octaviaflow/feature-flags",
3
+ "description": "Build with feature flags in OctaviaFlow",
4
+ "version": "1.0.0",
5
+ "license": "Apache-2.0",
6
+ "main": "lib/index.js",
7
+ "module": "es/index.js",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/octaviaflow-design-system.git",
11
+ "directory": "packages/feature-flags"
12
+ },
13
+ "bugs": "https://github.com/octaviaflow-design-system/issues",
14
+ "files": [
15
+ "es",
16
+ "lib",
17
+ "scss",
18
+ "index.scss",
19
+ "telemetry.yml"
20
+ ],
21
+ "keywords": [
22
+ "octaviaflow",
23
+ "feature-flags",
24
+ "components",
25
+ "react"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "build": "bun run clean && node tasks/build.js && rollup -c",
32
+ "clean": "rimraf es lib scss/generated src/generated",
33
+ "watch": "bun run clean && node tasks/build.js && rollup -c -w"
34
+ },
35
+ "devDependencies": {
36
+ "@babel/core": "^7.24.7",
37
+ "@babel/generator": "^7.24.7",
38
+ "@babel/preset-env": "^7.24.7",
39
+ "@babel/template": "^7.24.7",
40
+ "@babel/types": "^7.24.7",
41
+ "@octaviaflow/scss-generator": "^1.0.0",
42
+ "@rollup/plugin-babel": "^6.0.0",
43
+ "@rollup/plugin-node-resolve": "^15.0.0",
44
+ "change-case": "^4.1.2",
45
+ "fs-extra": "^11.0.0",
46
+ "js-yaml": "^3.14.0",
47
+ "rimraf": "^6.0.0",
48
+ "rollup": "^2.79.1",
49
+ "rollup-plugin-strip-banner": "^3.0.0"
50
+ },
51
+ "sideEffects": false,
52
+ "babel": {
53
+ "presets": [
54
+ "@babel/env"
55
+ ]
56
+ }
57
+ }
@@ -0,0 +1,21 @@
1
+ // Code generated by @octaviaflow/feature-flags. DO NOT EDIT.
2
+ //
3
+ // Copyright IBM Corp. 2015, 2023
4
+ //
5
+ // This source code is licensed under the Apache-2.0 license found in the
6
+ // LICENSE file in the root directory of this source tree.
7
+ //
8
+
9
+ $generated-feature-flags: (
10
+ 'enable-css-custom-properties': false,
11
+ 'enable-css-grid': false,
12
+ 'enable-v11-release': true,
13
+ 'enable-experimental-tile-contrast': false,
14
+ 'enable-v12-tile-default-icons': false,
15
+ 'enable-v12-tile-radio-icons': false,
16
+ 'enable-v12-overflowmenu': false,
17
+ 'enable-treeview-controllable': false,
18
+ 'enable-v12-structured-list-visible-icons': false,
19
+ 'enable-experimental-focus-wrap-without-sentinels': false,
20
+ 'enable-v12-dynamic-floating-styles': false,
21
+ );
package/telemetry.yml ADDED
@@ -0,0 +1,17 @@
1
+ # yaml-language-server: $schema=https://unpkg.com/@octaviaflow/telemetry-config-schema@v1.0.0/dist/config.schema.json
2
+ version: 1
3
+ projectId: 'eaa95bb4-28df-42d8-8ca1-58f7db07727b'
4
+ projectName: 'OctaviaFlow Feature Flags'
5
+ storage:
6
+ type: 'file'
7
+ file:
8
+ directory: '/Volumes/Main/Projects/OctaviaFlow-Design-System/telemetry-logs'
9
+ fileNamePattern: 'octaviaflow-feature-flags-{timestamp}.json'
10
+ maxFileSizeMB: 10
11
+ compress: false
12
+ collect:
13
+ npm:
14
+ dependencies: null
15
+ js:
16
+ functions: {}
17
+ tokens: null