@animus-ui/core 0.1.1-beta.9 → 0.1.1-e4cdacd2.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/dist/index.js ADDED
@@ -0,0 +1,1229 @@
1
+ import { isNumber, get, isArray, isObject, isString, isUndefined, identity, mapValues, omit, intersection, merge, pick, isEmpty, set, keys } from 'lodash';
2
+ import styled from '@emotion/styled';
3
+
4
+ const createScale = () => [];
5
+
6
+ const percentageOrAbsolute = (coordinate) => {
7
+ if (coordinate === 0) {
8
+ return coordinate;
9
+ }
10
+ if (coordinate <= 1 && coordinate >= -1) {
11
+ return `${coordinate * 100}%`;
12
+ }
13
+ return `${coordinate}px`;
14
+ };
15
+ const valueWithUnit = /(-?\d*\.?\d+)(%|\w*)/;
16
+ const size = (value) => {
17
+ if (isNumber(value)) {
18
+ return percentageOrAbsolute(value);
19
+ }
20
+ if (value.includes('calc')) {
21
+ return value;
22
+ }
23
+ const [match, number, unit] = valueWithUnit.exec(value) || [];
24
+ if (match === undefined) {
25
+ return value;
26
+ }
27
+ const numericValue = parseFloat(number);
28
+ return !unit ? percentageOrAbsolute(numericValue) : `${numericValue}${unit}`;
29
+ };
30
+
31
+ const gridItemMap = {
32
+ max: 'max-content',
33
+ min: 'min-content',
34
+ };
35
+ const unitlessNumber = new RegExp(/^[0-9]*$/);
36
+ const isUnitlessNumber = (val) => unitlessNumber.test(val);
37
+ const gridItem = (item) => {
38
+ const template = isUnitlessNumber(item)
39
+ ? `${item}fr`
40
+ : get(gridItemMap, item, item);
41
+ return `minmax(0, ${template})`;
42
+ };
43
+ const repeatGridItem = (item, count) => {
44
+ const template = gridItem(item);
45
+ return count > 1 ? `repeat(${count}, ${template})` : template;
46
+ };
47
+ const parseGridRatio = (val) => {
48
+ const items = val.split(':');
49
+ let repeated = ['', 0];
50
+ let gridStyle = '';
51
+ for (let i = 0; i < items.length + 1; i += 1) {
52
+ const delimiter = gridStyle.length > 0 ? ' ' : '';
53
+ const curr = items[i];
54
+ if (repeated?.[0] !== curr) {
55
+ if (repeated[0].length)
56
+ gridStyle += delimiter + repeatGridItem(...repeated);
57
+ if (curr)
58
+ repeated = [curr, 1];
59
+ }
60
+ else {
61
+ repeated[1] += 1;
62
+ }
63
+ }
64
+ return gridStyle;
65
+ };
66
+ const gridItemRatio = (val) => {
67
+ return isNumber(val) ? repeatGridItem('1', val) : parseGridRatio(val);
68
+ };
69
+
70
+ const numberToTemplate = (val, template) => (typeof val === 'number' ? template(val) : val);
71
+ const numberToPx = (val) => {
72
+ return numberToTemplate(val, (pixels) => `${pixels}px`);
73
+ };
74
+
75
+ const borderShorthand = (val) => {
76
+ return numberToTemplate(val, (width) => `${width}px solid currentColor`);
77
+ };
78
+
79
+ const compatTheme = {
80
+ breakpoints: {
81
+ xs: 480,
82
+ sm: 768,
83
+ md: 1024,
84
+ lg: 1200,
85
+ xl: 1440,
86
+ },
87
+ spacing: [0, 4, 8, 12, 16, 24, 32, 40, 48, 64, 96],
88
+ fontSize: [64, 44, 34, 26, 22, 20, 18, 16, 14],
89
+ lineHeight: {
90
+ body: 1.5,
91
+ heading: 1,
92
+ },
93
+ fontWeight: [400, 600, 700],
94
+ fontFamily: {
95
+ body: 'Verdana, sans-serif',
96
+ heading: 'Verdana, Lato, sans-serif',
97
+ monospace: 'monospace',
98
+ },
99
+ radii: [2, 4, 6, 8],
100
+ borders: [1, 2, 3],
101
+ colors: {},
102
+ modes: {},
103
+ mode: undefined,
104
+ };
105
+
106
+ const lookupScaleValue = (val, scale, theme) => {
107
+ if (isArray(scale)) {
108
+ return val;
109
+ }
110
+ if (isObject(scale)) {
111
+ return get(scale, val);
112
+ }
113
+ if (isString(scale)) {
114
+ const usedScale = get(theme, scale, get(compatTheme, scale));
115
+ if (!usedScale)
116
+ return undefined;
117
+ return isArray(usedScale) ? val : get(usedScale, val);
118
+ }
119
+ return undefined;
120
+ };
121
+
122
+ const createPropertyStyle = (value, props, config) => {
123
+ const styles = {};
124
+ const { transform = identity, property, properties = [property], scale, variable, } = config;
125
+ const alwaysTransform = scale === undefined || isArray(scale);
126
+ if (isUndefined(value)) {
127
+ return styles;
128
+ }
129
+ let useTransform = false;
130
+ let intermediateValue;
131
+ let scaleValue;
132
+ switch (typeof value) {
133
+ case 'number':
134
+ case 'string':
135
+ scaleValue = lookupScaleValue(value, scale, props?.theme);
136
+ useTransform = scaleValue !== undefined || alwaysTransform;
137
+ intermediateValue = scaleValue ?? value;
138
+ break;
139
+ case 'function':
140
+ if (props.theme) {
141
+ intermediateValue = value(props.theme);
142
+ }
143
+ break;
144
+ default:
145
+ return styles;
146
+ }
147
+ // for each property look up the scale value from theme if passed and apply any
148
+ // final transforms to the value
149
+ properties.forEach((property) => {
150
+ let styleValue = intermediateValue;
151
+ if (useTransform && !isUndefined(styleValue)) {
152
+ styleValue = transform(styleValue, property, props);
153
+ }
154
+ switch (typeof styleValue) {
155
+ case 'number':
156
+ case 'string':
157
+ return (styles[property] = styleValue);
158
+ case 'object':
159
+ return Object.assign(styles, styleValue);
160
+ }
161
+ });
162
+ if (variable) {
163
+ let styleValue = intermediateValue;
164
+ if (useTransform && !isUndefined(styleValue)) {
165
+ styleValue = transform(styleValue, property, props);
166
+ }
167
+ if (styleValue && typeof styleValue !== 'object') {
168
+ styles[variable] = styleValue;
169
+ }
170
+ }
171
+ // return the resulting styles object
172
+ return styles;
173
+ };
174
+
175
+ const SHORTHAND_PROPERTIES = [
176
+ 'border',
177
+ 'borderTop',
178
+ 'borderBottom',
179
+ 'borderLeft',
180
+ 'borderRight',
181
+ 'borderWidth',
182
+ 'borderStyle',
183
+ 'borderColor',
184
+ 'background',
185
+ 'flex',
186
+ 'margin',
187
+ 'padding',
188
+ 'transition',
189
+ 'gap',
190
+ 'grid',
191
+ 'gridArea',
192
+ 'gridColumn',
193
+ 'gridRow',
194
+ 'gridTemplate',
195
+ 'overflow',
196
+ 'transition',
197
+ ];
198
+ const SORT = {
199
+ A_BEFORE_B: -1,
200
+ B_BEFORE_A: 1,
201
+ EQUAL: 1,
202
+ };
203
+ const compare = (a, b) => {
204
+ if (a < b)
205
+ return SORT.A_BEFORE_B;
206
+ if (b < a)
207
+ return SORT.B_BEFORE_A;
208
+ return SORT.EQUAL;
209
+ };
210
+ /**
211
+ * Orders all properties by the most dependent props
212
+ * @param config
213
+ */
214
+ const orderPropNames = (config) => Object.keys(config).sort((a, b) => {
215
+ const { [a]: aConf, [b]: bConf } = config;
216
+ const { property: aProp, properties: aProperties = [] } = aConf;
217
+ const { property: bProp, properties: bProperties = [] } = bConf;
218
+ const aIsShorthand = SHORTHAND_PROPERTIES.includes(aProp);
219
+ const bIsShorthand = SHORTHAND_PROPERTIES.includes(bProp);
220
+ if (aIsShorthand && bIsShorthand) {
221
+ const aNum = aProperties.length;
222
+ const bNum = bProperties.length;
223
+ if (aProp !== bProp) {
224
+ return compare(SHORTHAND_PROPERTIES.indexOf(aProp), SHORTHAND_PROPERTIES.indexOf(bProp));
225
+ }
226
+ if (aProp === bProp) {
227
+ if (aNum === 0)
228
+ return SORT.A_BEFORE_B;
229
+ if (bNum === 0)
230
+ return SORT.B_BEFORE_A;
231
+ }
232
+ return compare(bNum, aNum);
233
+ }
234
+ if (aIsShorthand)
235
+ return SORT.A_BEFORE_B;
236
+ if (bIsShorthand)
237
+ return SORT.B_BEFORE_A;
238
+ return SORT.EQUAL;
239
+ });
240
+
241
+ const BREAKPOINT_KEYS$1 = ['_', 'xs', 'sm', 'md', 'lg', 'xl'];
242
+ /**
243
+ * Destructures the themes breakpoints into an ordered structure to traverse
244
+ */
245
+ const templateMediaQuery$1 = (breakpoint) => `@media screen and (min-width: ${breakpoint}px)`;
246
+ const createMediaQueries$1 = (breakpoints) => {
247
+ if (breakpoints === undefined)
248
+ return null;
249
+ const { xs, sm, md, lg, xl } = breakpoints ?? {};
250
+ // Ensure order for mapping
251
+ return {
252
+ map: mapValues(breakpoints, templateMediaQuery$1),
253
+ array: [xs, sm, md, lg, xl].map(templateMediaQuery$1),
254
+ };
255
+ };
256
+ const isMediaArray$1 = (val) => Array.isArray(val);
257
+ const isMediaMap$1 = (val) => intersection(Object.keys(val), BREAKPOINT_KEYS$1).length > 0;
258
+ const objectParser$1 = (value, props, config, breakpoints) => {
259
+ const styles = {};
260
+ const { _, ...rest } = value;
261
+ // the keyof 'base' is base styles
262
+ if (_)
263
+ Object.assign(styles, createPropertyStyle(_, props, config));
264
+ // Map over remaining keys and merge the corresponding breakpoint styles
265
+ // for that property.
266
+ Object.keys(breakpoints).forEach((breakpointKey) => {
267
+ const bpStyles = rest[breakpointKey];
268
+ if (typeof bpStyles === 'undefined')
269
+ return;
270
+ Object.assign(styles, {
271
+ [breakpoints[breakpointKey]]: createPropertyStyle(bpStyles, props, config),
272
+ });
273
+ });
274
+ return styles;
275
+ };
276
+ const arrayParser$1 = (value, props, config, breakpoints) => {
277
+ const styles = {};
278
+ const [_, ...rest] = value;
279
+ // the first index is base styles
280
+ if (_)
281
+ Object.assign(styles, createPropertyStyle(_, props, config));
282
+ // Map over each value in the array and merge the corresponding breakpoint styles
283
+ // for that property.
284
+ rest.forEach((val, i) => {
285
+ const breakpointKey = breakpoints[i];
286
+ if (!breakpointKey || typeof val === 'undefined')
287
+ return;
288
+ Object.assign(styles, {
289
+ [breakpointKey]: createPropertyStyle(val, props, config),
290
+ });
291
+ });
292
+ return styles;
293
+ };
294
+ const orderBreakpoints$1 = (styles, breakpoints) => {
295
+ const orderedStyles = omit(styles, breakpoints);
296
+ breakpoints.forEach((bp) => {
297
+ if (styles[bp]) {
298
+ orderedStyles[bp] = styles[bp];
299
+ }
300
+ });
301
+ return orderedStyles;
302
+ };
303
+
304
+ const renderPropValue$1 = (styles, prop, props, property, ctx) => {
305
+ const value = get(props, prop);
306
+ switch (typeof value) {
307
+ case 'string':
308
+ case 'number':
309
+ case 'function':
310
+ return Object.assign(styles, createPropertyStyle(value, props, property));
311
+ // handle any props configured with the responsive notation
312
+ case 'object':
313
+ if (!ctx.mediaQueries) {
314
+ return;
315
+ }
316
+ // If it is an array the order of values is smallest to largest: [_, xs, ...]
317
+ if (isMediaArray$1(value)) {
318
+ return merge(styles, arrayParser$1(value, props, property, ctx.mediaQueries.array));
319
+ }
320
+ // Check to see if value is an object matching the responsive syntax and generate the styles.
321
+ if (value && isMediaMap$1(value)) {
322
+ return merge(styles, objectParser$1(value, props, property, ctx.mediaQueries.map));
323
+ }
324
+ }
325
+ };
326
+ function createParser$1(config) {
327
+ const propNames = orderPropNames(config);
328
+ const ctx = {
329
+ mediaQueries: null,
330
+ };
331
+ const parser = (props, isCss = false) => {
332
+ const styles = {};
333
+ const { theme } = props;
334
+ // Attempt to cache the breakpoints if we have not yet or if theme has become available.
335
+ if (ctx.mediaQueries === null) {
336
+ // Save the breakpoints if we can
337
+ ctx.mediaQueries = createMediaQueries$1(theme?.breakpoints ?? compatTheme.breakpoints);
338
+ }
339
+ if (!isCss) {
340
+ // Loops over all prop names on the configured config to check for configured styles
341
+ propNames.forEach((prop) => {
342
+ const property = config[prop];
343
+ renderPropValue$1(styles, prop, props, property, ctx);
344
+ });
345
+ }
346
+ else {
347
+ // Loops over all prop names on the configured config to check for configured styles
348
+ Object.keys(props).forEach((prop) => {
349
+ const property = config[prop];
350
+ if (property) {
351
+ renderPropValue$1(styles, prop, props, property, ctx);
352
+ }
353
+ else if (prop !== 'theme') {
354
+ Object.assign(styles, { [prop]: get(props, prop) });
355
+ }
356
+ });
357
+ }
358
+ if (ctx.mediaQueries !== null)
359
+ return orderBreakpoints$1(styles, ctx.mediaQueries.array);
360
+ return styles;
361
+ };
362
+ // return the parser function with the resulting meta information for further composition
363
+ return Object.assign(parser, { propNames, config });
364
+ }
365
+
366
+ /* eslint-disable guard-for-in */
367
+ const getSelectors = (base = {}, variants = {}, states = {}, filters) => {
368
+ const rules = {};
369
+ Object.entries(base).forEach(([key, styles]) => {
370
+ if (!filters.includes(key) && isObject(styles)) {
371
+ set(rules, [key, 'base'], styles);
372
+ }
373
+ else {
374
+ set(rules, ['primary', 'base', key], styles);
375
+ }
376
+ });
377
+ Object.entries(variants).forEach(([key, { variants: variantConfig }]) => {
378
+ Object.entries(variantConfig).forEach(([option, optionStyles]) => {
379
+ const optionId = `${key}-${option}`;
380
+ Object.entries(optionStyles).forEach(([key, styles]) => {
381
+ if (!filters.includes(key) && isObject(styles)) {
382
+ set(rules, [key, optionId], styles);
383
+ }
384
+ else {
385
+ set(rules, ['primary', optionId, key], styles);
386
+ }
387
+ });
388
+ });
389
+ });
390
+ Object.entries(states).forEach(([optionId, optionStyles]) => {
391
+ Object.entries(optionStyles).forEach(([key, styles]) => {
392
+ if (!filters.includes(key) && isObject(styles)) {
393
+ set(rules, [key, optionId], styles);
394
+ }
395
+ else {
396
+ set(rules, ['primary', optionId, key], styles);
397
+ }
398
+ });
399
+ });
400
+ return rules;
401
+ };
402
+ const createGetActiveStyleIds = (variants, states) => {
403
+ const vIds = Object.keys(variants);
404
+ const sIds = Object.keys(states);
405
+ return (props) => {
406
+ const activeIds = [];
407
+ vIds.forEach((id) => {
408
+ if (props[id]) {
409
+ activeIds.push(`${id}-${props[id]}`);
410
+ }
411
+ });
412
+ sIds.forEach((id) => {
413
+ if (props[id]) {
414
+ activeIds.push(id);
415
+ }
416
+ });
417
+ return activeIds;
418
+ };
419
+ };
420
+ const extractBreakpointStyles = (styles, medias) => {
421
+ const unscoped = {};
422
+ const breakpoint = {};
423
+ Object.entries(styles).forEach(([rule, value]) => {
424
+ const target = medias.includes(rule) ? breakpoint : unscoped;
425
+ target[rule] = value;
426
+ });
427
+ return [unscoped, breakpoint];
428
+ };
429
+ const applyOverride = (override = {}, baseResult, breakpointResult, parser, theme, media) => {
430
+ const [overrideStyles, overrideBreakpointStyles] = extractBreakpointStyles(parser({ ...override, theme }, true), media);
431
+ for (const rule in overrideStyles) {
432
+ baseResult[rule] = overrideStyles[rule];
433
+ }
434
+ media.forEach((mq) => {
435
+ const mqOverride = overrideBreakpointStyles[mq];
436
+ if (!mqOverride || isEmpty(mqOverride))
437
+ return;
438
+ if (!breakpointResult[mq]) {
439
+ breakpointResult[mq] = {};
440
+ }
441
+ const mqStyle = breakpointResult[mq];
442
+ for (const rule in mqOverride) {
443
+ mqStyle[rule] = mqOverride[rule];
444
+ }
445
+ });
446
+ };
447
+ const applyStyle = (resultStyles, config, props, ctx) => {
448
+ const { base } = config;
449
+ const { parser, getMediaSelectors, getActiveOverrides } = ctx;
450
+ const { theme } = props;
451
+ const overrides = Object.values(pick(config, getActiveOverrides(props)));
452
+ const media = getMediaSelectors(props);
453
+ const [styles, breakpointStyles] = extractBreakpointStyles(parser({ ...base, theme }, true), media);
454
+ for (const rule in styles) {
455
+ resultStyles[rule] = styles[rule];
456
+ }
457
+ overrides.forEach((override) => {
458
+ applyOverride(override, resultStyles, breakpointStyles, parser, theme, media);
459
+ });
460
+ media.forEach((media) => {
461
+ const bp = breakpointStyles[media];
462
+ if (!isEmpty(bp)) {
463
+ resultStyles[media] = bp;
464
+ }
465
+ });
466
+ };
467
+ const createStylist = (parser, base = {}, variants = {}, states = {}) => {
468
+ const selectorGroups = getSelectors(base, variants, states, parser.propNames);
469
+ const context = {
470
+ parser,
471
+ getMediaSelectors: ({ theme }) => {
472
+ const breakpoints = theme?.breakpoints ?? compatTheme.breakpoints;
473
+ return ['xs', 'sm', 'md', 'lg', 'xl'].map((key) => breakpoints[key]);
474
+ },
475
+ getActiveOverrides: createGetActiveStyleIds(variants, states),
476
+ };
477
+ return (props) => {
478
+ const { vars } = props;
479
+ const result = { ...vars };
480
+ Object.entries(selectorGroups).forEach(([selectorId, config = {}]) => {
481
+ if (selectorId === 'primary') {
482
+ applyStyle(result, config, props, context);
483
+ }
484
+ else {
485
+ result[selectorId] = {};
486
+ applyStyle(result[selectorId], config, props, context);
487
+ }
488
+ });
489
+ applyStyle(result, { base: parser(props) }, props, context);
490
+ return result;
491
+ };
492
+ };
493
+
494
+ class AnimusWithAll {
495
+ propRegistry = {};
496
+ groupRegistry = {};
497
+ parser = {};
498
+ baseStyles = {};
499
+ statesConfig = {};
500
+ variants = {};
501
+ activeGroups = {};
502
+ custom = {};
503
+ constructor(props, groups, parser, base, variants, states, activeGroups, custom) {
504
+ this.propRegistry = props;
505
+ this.groupRegistry = groups;
506
+ this.parser = parser;
507
+ this.baseStyles = base;
508
+ this.variants = variants;
509
+ this.statesConfig = states;
510
+ this.activeGroups = activeGroups;
511
+ this.custom = custom;
512
+ }
513
+ asComponent(component) {
514
+ const handler = createStylist(createParser$1({ ...this.parser.config, ...this.custom }), this.baseStyles, this.variants, this.statesConfig);
515
+ return styled(component)(handler);
516
+ }
517
+ build() {
518
+ const handler = createStylist(createParser$1({ ...this.parser.config, ...this.custom }), this.baseStyles, this.variants, this.statesConfig);
519
+ return handler;
520
+ }
521
+ }
522
+ class AnimusWithSystem extends AnimusWithAll {
523
+ constructor(props, groups, parser, base, variants, states, activeGroups) {
524
+ super(props, groups, parser, base, variants, states, activeGroups, {});
525
+ }
526
+ props(config) {
527
+ return new AnimusWithAll(this.propRegistry, this.groupRegistry, this.parser, this.baseStyles, this.variants, this.statesConfig, this.activeGroups, config);
528
+ }
529
+ }
530
+ class AnimusWithStates extends AnimusWithSystem {
531
+ constructor(props, groups, parser, base, variants, states) {
532
+ super(props, groups, parser, base, variants, states, {});
533
+ }
534
+ groups(config) {
535
+ return new AnimusWithSystem(this.propRegistry, this.groupRegistry, this.parser, this.baseStyles, this.variants, this.statesConfig, config);
536
+ }
537
+ }
538
+ class AnimusWithVariants extends AnimusWithStates {
539
+ constructor(props, groups, parser, base, variants) {
540
+ super(props, groups, parser, base, variants, {});
541
+ }
542
+ states(config) {
543
+ return new AnimusWithStates(this.propRegistry, this.groupRegistry, this.parser, this.baseStyles, this.variants, config);
544
+ }
545
+ variant(options) {
546
+ const prop = options.prop || 'variant';
547
+ return new AnimusWithVariants(this.propRegistry, this.groupRegistry, this.parser, this.baseStyles, merge(this.variants, { [prop]: options }));
548
+ }
549
+ }
550
+ class AnimusWithBase extends AnimusWithVariants {
551
+ constructor(props, groups, parser, base) {
552
+ super(props, groups, parser, base, {});
553
+ }
554
+ variant(options) {
555
+ const prop = options.prop || 'variant';
556
+ return new AnimusWithVariants(this.propRegistry, this.groupRegistry, this.parser, this.baseStyles, merge(this.variants, { [prop]: options }));
557
+ }
558
+ }
559
+ class Animus extends AnimusWithBase {
560
+ constructor(props, groups) {
561
+ super(props, groups, createParser$1(props), {});
562
+ }
563
+ styles(config) {
564
+ return new AnimusWithBase(this.propRegistry, this.groupRegistry, this.parser, config);
565
+ }
566
+ }
567
+
568
+ class AnimusConfig {
569
+ #props = {};
570
+ #groups = {};
571
+ constructor(config, groups) {
572
+ this.#props = config || {};
573
+ this.#groups = groups || {};
574
+ }
575
+ addGroup(name, config) {
576
+ const newGroup = {
577
+ [name]: Object.keys(config),
578
+ };
579
+ return new AnimusConfig({ ...this.#props, ...config }, { ...this.#groups, ...newGroup });
580
+ }
581
+ build() {
582
+ const props = this.#props;
583
+ const groups = this.#groups;
584
+ return new Animus(props, groups);
585
+ }
586
+ }
587
+
588
+ const createAnimus = () => new AnimusConfig();
589
+
590
+ const color = {
591
+ color: { property: 'color', scale: 'colors' },
592
+ textColor: { property: 'color', scale: 'colors' },
593
+ bg: { property: 'backgroundColor', scale: 'colors' },
594
+ borderColor: { property: 'borderColor', scale: 'colors' },
595
+ borderColorX: {
596
+ property: 'borderColor',
597
+ properties: ['borderLeftColor', 'borderRightColor'],
598
+ scale: 'colors',
599
+ },
600
+ borderColorY: {
601
+ property: 'borderColor',
602
+ properties: ['borderTopColor', 'borderBottomColor'],
603
+ scale: 'colors',
604
+ },
605
+ borderColorLeft: { property: 'borderLeftColor', scale: 'colors' },
606
+ borderColorRight: { property: 'borderRightColor', scale: 'colors' },
607
+ borderColorTop: { property: 'borderTopColor', scale: 'colors' },
608
+ borderColorBottom: { property: 'borderBottomColor', scale: 'colors' },
609
+ };
610
+ const border = {
611
+ border: {
612
+ property: 'border',
613
+ scale: 'borders',
614
+ transform: borderShorthand,
615
+ },
616
+ borderX: {
617
+ property: 'border',
618
+ properties: ['borderLeft', 'borderRight'],
619
+ scale: 'borders',
620
+ transform: borderShorthand,
621
+ },
622
+ borderY: {
623
+ property: 'border',
624
+ properties: ['borderTop', 'borderBottom'],
625
+ scale: 'borders',
626
+ transform: borderShorthand,
627
+ },
628
+ borderTop: {
629
+ property: 'borderTop',
630
+ scale: 'borders',
631
+ transform: borderShorthand,
632
+ },
633
+ borderRight: {
634
+ property: 'borderRight',
635
+ scale: 'borders',
636
+ transform: borderShorthand,
637
+ },
638
+ borderBottom: {
639
+ property: 'borderBottom',
640
+ scale: 'borders',
641
+ transform: borderShorthand,
642
+ },
643
+ borderLeft: {
644
+ property: 'borderLeft',
645
+ scale: 'borders',
646
+ transform: borderShorthand,
647
+ },
648
+ // Width
649
+ borderWidth: { property: 'borderWidth' },
650
+ borderWidthX: {
651
+ property: 'borderWidth',
652
+ properties: ['borderLeftWidth', 'borderRightWidth'],
653
+ },
654
+ borderWidthY: {
655
+ property: 'borderWidth',
656
+ properties: ['borderTopWidth', 'borderBottomWidth'],
657
+ },
658
+ borderWidthLeft: { property: 'borderLeftWidth' },
659
+ borderWidthRight: { property: 'borderRightWidth' },
660
+ borderWidthTop: { property: 'borderTopWidth' },
661
+ borderWidthBottom: { property: 'borderBottomWidth' },
662
+ // Radius
663
+ borderRadius: {
664
+ property: 'borderRadius',
665
+ scale: 'radii',
666
+ transform: numberToPx,
667
+ },
668
+ borderRadiusLeft: {
669
+ property: 'borderRadius',
670
+ properties: ['borderTopLeftRadius', 'borderBottomLeftRadius'],
671
+ scale: 'radii',
672
+ transform: numberToPx,
673
+ },
674
+ borderRadiusTop: {
675
+ property: 'borderRadius',
676
+ properties: ['borderTopLeftRadius', 'borderTopRightRadius'],
677
+ scale: 'radii',
678
+ transform: numberToPx,
679
+ },
680
+ borderRadiusBottom: {
681
+ property: 'borderRadius',
682
+ properties: ['borderBottomLeftRadius', 'borderBottomRightRadius'],
683
+ scale: 'radii',
684
+ transform: numberToPx,
685
+ },
686
+ borderRadiusRight: {
687
+ property: 'borderRadius',
688
+ properties: ['borderTopRightRadius', 'borderBottomRightRadius'],
689
+ scale: 'radii',
690
+ transform: numberToPx,
691
+ },
692
+ borderRadiusTopLeft: {
693
+ property: 'borderTopLeftRadius',
694
+ scale: 'radii',
695
+ transform: numberToPx,
696
+ },
697
+ borderRadiusTopRight: {
698
+ property: 'borderTopRightRadius',
699
+ scale: 'radii',
700
+ transform: numberToPx,
701
+ },
702
+ borderRadiusBottomRight: {
703
+ property: 'borderBottomRightRadius',
704
+ scale: 'radii',
705
+ transform: numberToPx,
706
+ },
707
+ borderRadiusBottomLeft: {
708
+ property: 'borderBottomLeftRadius',
709
+ scale: 'radii',
710
+ transform: numberToPx,
711
+ },
712
+ // Style
713
+ borderStyle: { property: 'borderStyle' },
714
+ borderStyleX: {
715
+ property: 'borderStyle',
716
+ properties: ['borderLeftStyle', 'borderRightStyle'],
717
+ },
718
+ borderStyleY: {
719
+ property: 'borderStyle',
720
+ properties: ['borderTopStyle', 'borderBottomStyle'],
721
+ },
722
+ borderStyleLeft: { property: 'borderLeftStyle' },
723
+ borderStyleRight: { property: 'borderRightStyle' },
724
+ borderStyleTop: { property: 'borderTopStyle' },
725
+ borderStyleBottom: { property: 'borderBottomStyle' },
726
+ };
727
+ const gaps = {
728
+ gap: { property: 'gap', scale: 'spacing' },
729
+ rowGap: { property: 'rowGap', scale: 'spacing' },
730
+ columnGap: { property: 'columnGap', scale: 'spacing' },
731
+ };
732
+ const selfAlignments = {
733
+ justifySelf: { property: 'justifySelf' },
734
+ alignSelf: { property: 'alignSelf' },
735
+ gridArea: { property: 'gridArea' },
736
+ area: { property: 'gridArea' },
737
+ };
738
+ const alignments = {
739
+ justifyContent: { property: 'justifyContent' },
740
+ justifyItems: { property: 'justifyItems' },
741
+ alignItems: { property: 'alignItems' },
742
+ alignContent: { property: 'alignContent' },
743
+ ...selfAlignments,
744
+ };
745
+ const flexItems = {
746
+ flexBasis: { property: 'flexBasis' },
747
+ flexShrink: { property: 'flexShrink' },
748
+ flexGrow: { property: 'flexGrow' },
749
+ order: { property: 'order' },
750
+ };
751
+ const flex = {
752
+ flexDirection: { property: 'flexDirection' },
753
+ flexWrap: { property: 'flexWrap' },
754
+ flex: { property: 'flex' },
755
+ ...alignments,
756
+ ...flexItems,
757
+ ...gaps,
758
+ };
759
+ const gridItems = {
760
+ gridColumn: { property: 'gridColumn' },
761
+ gridRow: { property: 'gridRow' },
762
+ gridColumnStart: { property: 'gridColumnStart' },
763
+ gridRowStart: { property: 'gridRowStart' },
764
+ gridColumnEnd: { property: 'gridColumnEnd' },
765
+ gridRowEnd: { property: 'gridRowEnd' },
766
+ };
767
+ const grid = {
768
+ gridAutoColumns: { property: 'gridAutoColumns' },
769
+ gridAutoRows: { property: 'gridAutoRows' },
770
+ gridTemplateColumns: { property: 'gridTemplateColumns' },
771
+ gridTemplateRows: { property: 'gridTemplateRows' },
772
+ gridTemplateAreas: { property: 'gridTemplateAreas' },
773
+ gridAutoFlow: { property: 'gridAutoFlow' },
774
+ flow: {
775
+ property: 'gridAutoFlow',
776
+ scale: createScale(),
777
+ },
778
+ cols: {
779
+ property: 'gridTemplateColumns',
780
+ transform: gridItemRatio,
781
+ scale: createScale(),
782
+ },
783
+ rows: {
784
+ property: 'gridTemplateRows',
785
+ transform: gridItemRatio,
786
+ scale: createScale(),
787
+ },
788
+ autoRows: {
789
+ property: 'gridAutoRows',
790
+ transform: gridItem,
791
+ },
792
+ autoCols: {
793
+ property: 'gridAutoColumns',
794
+ transform: gridItem,
795
+ },
796
+ alignAll: {
797
+ property: 'justifyContent',
798
+ properties: ['justifyContent', 'alignItems'],
799
+ },
800
+ ...alignments,
801
+ ...gridItems,
802
+ ...gaps,
803
+ };
804
+ const background = {
805
+ background: { property: 'background' },
806
+ backgroundImage: { property: 'backgroundImage' },
807
+ backgroundSize: { property: 'backgroundSize' },
808
+ backgroundRepeat: { property: 'backgroundRepeat' },
809
+ backgroundPosition: { property: 'backgroundPosition' },
810
+ };
811
+ const positioning = {
812
+ position: { property: 'position' },
813
+ inset: {
814
+ property: 'inset',
815
+ properties: ['top', 'right', 'bottom', 'left'],
816
+ transform: size,
817
+ },
818
+ top: { property: 'top', transform: size },
819
+ right: { property: 'right', transform: size },
820
+ bottom: { property: 'bottom', transform: size },
821
+ left: { property: 'left', transform: size },
822
+ zIndex: { property: 'zIndex' },
823
+ opacity: { property: 'opacity' },
824
+ };
825
+ const shadows = {
826
+ boxShadow: { property: 'boxShadow' },
827
+ textShadow: { property: 'textShadow' },
828
+ };
829
+ const layout = {
830
+ display: { property: 'display' },
831
+ overflow: { property: 'overflow' },
832
+ overflowX: { property: 'overflowX' },
833
+ overflowY: { property: 'overflowY' },
834
+ size: {
835
+ property: 'width',
836
+ properties: ['width', 'height'],
837
+ transform: size,
838
+ },
839
+ width: {
840
+ property: 'width',
841
+ transform: size,
842
+ },
843
+ minWidth: { property: 'minWidth', transform: size },
844
+ maxWidth: { property: 'maxWidth', transform: size },
845
+ height: { property: 'height', transform: size },
846
+ minHeight: {
847
+ property: 'minHeight',
848
+ transform: size,
849
+ },
850
+ maxHeight: {
851
+ property: 'maxHeight',
852
+ transform: size,
853
+ },
854
+ verticalAlign: { property: 'verticalAlign' },
855
+ ...selfAlignments,
856
+ ...gridItems,
857
+ ...flexItems,
858
+ };
859
+ const typography = {
860
+ fontFamily: { property: 'fontFamily', scale: 'fontFamily' },
861
+ fontWeight: {
862
+ property: 'fontWeight',
863
+ scale: 'fontWeight',
864
+ },
865
+ lineHeight: {
866
+ property: 'lineHeight',
867
+ scale: 'lineHeight',
868
+ lineHeight: 'lineHeight',
869
+ },
870
+ fontSize: {
871
+ property: 'fontSize',
872
+ scale: 'fontSize',
873
+ },
874
+ letterSpacing: { property: 'letterSpacing' },
875
+ textAlign: { property: 'textAlign' },
876
+ fontStyle: { property: 'fontStyle' },
877
+ textDecoration: { property: 'textDecoration' },
878
+ textTransform: { property: 'textTransform' },
879
+ whiteSpace: { property: 'whiteSpace' },
880
+ };
881
+ const margin = {
882
+ m: { property: 'margin', scale: 'spacing' },
883
+ mx: {
884
+ property: 'margin',
885
+ properties: ['marginLeft', 'marginRight'],
886
+ scale: 'spacing',
887
+ },
888
+ my: {
889
+ property: 'margin',
890
+ properties: ['marginTop', 'marginBottom'],
891
+ scale: 'spacing',
892
+ },
893
+ mt: { property: 'marginTop', scale: 'spacing' },
894
+ mb: { property: 'marginBottom', scale: 'spacing' },
895
+ mr: { property: 'marginRight', scale: 'spacing' },
896
+ ml: { property: 'marginLeft', scale: 'spacing' },
897
+ };
898
+ const padding = {
899
+ p: { property: 'padding', scale: 'spacing' },
900
+ px: {
901
+ property: 'padding',
902
+ properties: ['paddingLeft', 'paddingRight'],
903
+ scale: 'spacing',
904
+ },
905
+ py: {
906
+ property: 'padding',
907
+ properties: ['paddingTop', 'paddingBottom'],
908
+ scale: 'spacing',
909
+ },
910
+ pt: { property: 'paddingTop', scale: 'spacing' },
911
+ pb: { property: 'paddingBottom', scale: 'spacing' },
912
+ pr: { property: 'paddingRight', scale: 'spacing' },
913
+ pl: { property: 'paddingLeft', scale: 'spacing' },
914
+ };
915
+ const space = {
916
+ ...margin,
917
+ ...padding,
918
+ };
919
+ const mode = {
920
+ mode: { property: 'none', scale: 'mode' },
921
+ };
922
+ const vars = {
923
+ vars: { property: 'variables' },
924
+ };
925
+ const config = createAnimus()
926
+ .addGroup('flex', flex)
927
+ .addGroup('grid', grid)
928
+ .addGroup('mode', mode)
929
+ .addGroup('vars', vars)
930
+ .addGroup('space', space)
931
+ .addGroup('color', color)
932
+ .addGroup('layout', layout)
933
+ .addGroup('borders', border)
934
+ .addGroup('shadows', shadows)
935
+ .addGroup('background', background)
936
+ .addGroup('typography', typography)
937
+ .addGroup('positioning', positioning);
938
+ config.build();
939
+
940
+ const getStylePropNames = (props, filteredKeys) => pick(props, keys(props).filter((key) => !filteredKeys.includes(key)));
941
+
942
+ const BREAKPOINT_KEYS = ['_', 'xs', 'sm', 'md', 'lg', 'xl'];
943
+ /**
944
+ * Destructures the themes breakpoints into an ordered structure to traverse
945
+ */
946
+ const templateMediaQuery = (breakpoint) => `@media screen and (min-width: ${breakpoint}px)`;
947
+ const createMediaQueries = (breakpoints) => {
948
+ if (breakpoints === undefined)
949
+ return null;
950
+ const { xs, sm, md, lg, xl } = breakpoints ?? {};
951
+ // Ensure order for mapping
952
+ return {
953
+ map: mapValues(breakpoints, templateMediaQuery),
954
+ array: [xs, sm, md, lg, xl].map(templateMediaQuery),
955
+ };
956
+ };
957
+ const isMediaArray = (val) => Array.isArray(val);
958
+ const isMediaMap = (val) => intersection(Object.keys(val), BREAKPOINT_KEYS).length > 0;
959
+ const objectParser = (value, props, config, breakpoints) => {
960
+ const styles = {};
961
+ const { styleFn, prop } = config;
962
+ const { _, ...rest } = value;
963
+ // the keyof 'base' is base styles
964
+ if (_)
965
+ Object.assign(styles, styleFn(_, prop, props));
966
+ // Map over remaining keys and merge the corresponding breakpoint styles
967
+ // for that property.
968
+ Object.keys(breakpoints).forEach((breakpointKey) => {
969
+ const bpStyles = rest[breakpointKey];
970
+ if (typeof bpStyles === 'undefined')
971
+ return;
972
+ Object.assign(styles, {
973
+ [breakpoints[breakpointKey]]: styleFn(bpStyles, prop, props),
974
+ });
975
+ });
976
+ return styles;
977
+ };
978
+ const arrayParser = (value, props, config, breakpoints) => {
979
+ const styles = {};
980
+ const { styleFn, prop } = config;
981
+ const [_, ...rest] = value;
982
+ // the first index is base styles
983
+ if (_)
984
+ Object.assign(styles, styleFn(_, prop, props));
985
+ // Map over each value in the array and merge the corresponding breakpoint styles
986
+ // for that property.
987
+ rest.forEach((val, i) => {
988
+ const breakpointKey = breakpoints[i];
989
+ if (!breakpointKey || typeof val === 'undefined')
990
+ return;
991
+ Object.assign(styles, {
992
+ [breakpointKey]: styleFn(val, prop, props),
993
+ });
994
+ });
995
+ return styles;
996
+ };
997
+ const orderBreakpoints = (styles, breakpoints) => {
998
+ const orderedStyles = omit(styles, breakpoints);
999
+ breakpoints.forEach((bp) => {
1000
+ if (styles[bp]) {
1001
+ orderedStyles[bp] = styles[bp];
1002
+ }
1003
+ });
1004
+ return orderedStyles;
1005
+ };
1006
+
1007
+ const renderPropValue = (styles, prop, props, property, ctx) => {
1008
+ const value = get(props, prop);
1009
+ switch (typeof value) {
1010
+ case 'string':
1011
+ case 'number':
1012
+ case 'function':
1013
+ return Object.assign(styles, property.styleFn(value, prop, props));
1014
+ // handle any props configured with the responsive notation
1015
+ case 'object':
1016
+ if (!ctx.mediaQueries) {
1017
+ return;
1018
+ }
1019
+ // If it is an array the order of values is smallest to largest: [_, xs, ...]
1020
+ if (isMediaArray(value)) {
1021
+ return merge(styles, arrayParser(value, props, property, ctx.mediaQueries.array));
1022
+ }
1023
+ // Check to see if value is an object matching the responsive syntax and generate the styles.
1024
+ if (value && isMediaMap(value)) {
1025
+ return merge(styles, objectParser(value, props, property, ctx.mediaQueries.map));
1026
+ }
1027
+ }
1028
+ };
1029
+ function createParser(config) {
1030
+ const propNames = orderPropNames(config);
1031
+ const ctx = {
1032
+ mediaQueries: null,
1033
+ };
1034
+ const parser = (props, isCss = false) => {
1035
+ const styles = {};
1036
+ const { theme } = props;
1037
+ // Attempt to cache the breakpoints if we have not yet or if theme has become available.
1038
+ if (ctx.mediaQueries === null) {
1039
+ // Save the breakpoints if we can
1040
+ ctx.mediaQueries = createMediaQueries(theme?.breakpoints ?? compatTheme.breakpoints);
1041
+ }
1042
+ if (!isCss) {
1043
+ // Loops over all prop names on the configured config to check for configured styles
1044
+ propNames.forEach((prop) => {
1045
+ const property = config[prop];
1046
+ renderPropValue(styles, prop, props, property, ctx);
1047
+ });
1048
+ }
1049
+ else {
1050
+ // Loops over all prop names on the configured config to check for configured styles
1051
+ Object.keys(props).forEach((prop) => {
1052
+ const property = config[prop];
1053
+ if (property) {
1054
+ renderPropValue(styles, prop, props, property, ctx);
1055
+ }
1056
+ else if (prop !== 'theme') {
1057
+ Object.assign(styles, { [prop]: get(props, prop) });
1058
+ }
1059
+ });
1060
+ }
1061
+ if (ctx.mediaQueries !== null)
1062
+ return orderBreakpoints(styles, ctx.mediaQueries.array);
1063
+ return styles;
1064
+ };
1065
+ // return the parser function with the resulting meta information for further composition
1066
+ return Object.assign(parser, { propNames, config });
1067
+ }
1068
+
1069
+ function createTransform(prop, config) {
1070
+ const { transform = identity, property, properties = [property], scale, variable, } = config;
1071
+ const alwaysTransform = scale === undefined || isArray(scale);
1072
+ return {
1073
+ ...config,
1074
+ prop,
1075
+ styleFn: (value, prop, props) => {
1076
+ const styles = {};
1077
+ if (isUndefined(value)) {
1078
+ return styles;
1079
+ }
1080
+ let useTransform = false;
1081
+ let intermediateValue;
1082
+ let scaleValue;
1083
+ switch (typeof value) {
1084
+ case 'number':
1085
+ case 'string':
1086
+ scaleValue = lookupScaleValue(value, scale, props.theme);
1087
+ useTransform = scaleValue !== undefined || alwaysTransform;
1088
+ intermediateValue = scaleValue ?? value;
1089
+ break;
1090
+ case 'function':
1091
+ if (props.theme) {
1092
+ intermediateValue = value(props.theme);
1093
+ }
1094
+ break;
1095
+ default:
1096
+ return styles;
1097
+ }
1098
+ // for each property look up the scale value from theme if passed and apply any
1099
+ // final transforms to the value
1100
+ properties.forEach((property) => {
1101
+ let styleValue = intermediateValue;
1102
+ if (useTransform && !isUndefined(styleValue)) {
1103
+ styleValue = transform(styleValue, property, props);
1104
+ }
1105
+ switch (typeof styleValue) {
1106
+ case 'number':
1107
+ case 'string':
1108
+ return (styles[property] = styleValue);
1109
+ case 'object':
1110
+ return Object.assign(styles, styleValue);
1111
+ }
1112
+ });
1113
+ if (variable) {
1114
+ let styleValue = intermediateValue;
1115
+ if (useTransform && !isUndefined(styleValue)) {
1116
+ styleValue = transform(styleValue, property, props);
1117
+ }
1118
+ if (styleValue && typeof styleValue !== 'object') {
1119
+ styles[variable] = styleValue;
1120
+ }
1121
+ }
1122
+ // return the resulting styles object
1123
+ return styles;
1124
+ },
1125
+ };
1126
+ }
1127
+
1128
+ function create(config) {
1129
+ // Create a transform function for each of the props
1130
+ const transforms = {};
1131
+ for (const prop in config) {
1132
+ if (typeof prop === 'string') {
1133
+ transforms[prop] = createTransform(prop, config[prop]);
1134
+ }
1135
+ }
1136
+ // Create a parser that handles all the props within the config
1137
+ return createParser(transforms);
1138
+ }
1139
+
1140
+ function createCss(config) {
1141
+ const parser = create(config);
1142
+ const filteredProps = parser.propNames;
1143
+ return (cssProps) => {
1144
+ let cache;
1145
+ const allKeys = Object.keys(cssProps);
1146
+ /** Any key of the CSSProps that is not a System Prop or a Static CSS Property is treated as a nested selector */
1147
+ const selectors = allKeys.filter((key) => !filteredProps.includes(key) && isObject(cssProps[key]));
1148
+ /** Static CSS Properties get extracted if they match neither syntax */
1149
+ const staticCss = getStylePropNames(cssProps, [
1150
+ 'theme',
1151
+ ...selectors,
1152
+ ...filteredProps,
1153
+ ]);
1154
+ return ({ theme }) => {
1155
+ if (cache)
1156
+ return cache;
1157
+ const css = parser({ ...cssProps, theme });
1158
+ selectors.forEach((selector) => {
1159
+ const selectorConfig = cssProps[selector] ?? {};
1160
+ css[selector] = {
1161
+ ...getStylePropNames(selectorConfig, filteredProps),
1162
+ ...parser({ ...selectorConfig, theme }),
1163
+ };
1164
+ });
1165
+ /** Merge the static and generated css and save it to the cache */
1166
+ cache = {
1167
+ ...staticCss,
1168
+ ...css,
1169
+ };
1170
+ return cache;
1171
+ };
1172
+ };
1173
+ }
1174
+
1175
+ function createVariant(config) {
1176
+ const css = createCss(config);
1177
+ return ({ prop = 'variant', defaultVariant, base = {}, variants }) => {
1178
+ const baseFn = css(base);
1179
+ const variantFns = {};
1180
+ Object.keys(variants).forEach((key) => {
1181
+ const variantKey = key;
1182
+ const cssProps = variants[variantKey];
1183
+ variantFns[variantKey] = css(cssProps);
1184
+ });
1185
+ return (props) => {
1186
+ const { [prop]: selected = defaultVariant } = props;
1187
+ const styles = {};
1188
+ if (!selected)
1189
+ return styles;
1190
+ return merge(styles, baseFn(props), variantFns?.[selected]?.(props));
1191
+ };
1192
+ };
1193
+ }
1194
+
1195
+ function compose(...parsers) {
1196
+ return createParser(parsers.reduce((carry, parser) => ({ ...carry, ...parser.config }), {}));
1197
+ }
1198
+
1199
+ function createStates(config) {
1200
+ const css = createCss(config);
1201
+ return (states) => {
1202
+ const orderedStates = Object.keys(states);
1203
+ const stateFns = {};
1204
+ orderedStates.forEach((key) => {
1205
+ const stateKey = key;
1206
+ const cssProps = states[stateKey];
1207
+ stateFns[stateKey] = css(cssProps);
1208
+ });
1209
+ return (props) => {
1210
+ const styles = {};
1211
+ orderedStates.forEach((state) => {
1212
+ merge(styles, props[state] && stateFns[state](props));
1213
+ });
1214
+ return styles;
1215
+ };
1216
+ };
1217
+ }
1218
+
1219
+ const animusProps = {
1220
+ compose,
1221
+ create,
1222
+ createCss,
1223
+ createVariant,
1224
+ createStates,
1225
+ };
1226
+
1227
+ const animus = config.build();
1228
+
1229
+ export { AnimusConfig, animus, animusProps, borderShorthand, compatTheme, config, createAnimus, createScale, gridItem, gridItemRatio, numberToPx, numberToTemplate, parseGridRatio, percentageOrAbsolute, repeatGridItem, size };