@appartmint/mint 0.12.26 → 0.12.30

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.
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Object functions for the util library
3
+ */
4
+ export abstract class mintObject {
5
+ /**
6
+ * Returns true if the provided objects have the same entries
7
+ */
8
+ static isSimilar (obj1: any, obj2: any) : boolean {
9
+ let keys: string[] = Object.keys(obj1);
10
+ if (keys.length !== Object.keys(obj2).length) {
11
+ return false;
12
+ }
13
+ let isSimilar: boolean = true;
14
+ keys.forEach((key: string) => {
15
+ if (obj1[key] !== obj2[key]) {
16
+ isSimilar = false;
17
+ }
18
+ });
19
+ return isSimilar;
20
+ };
21
+
22
+ /**
23
+ * Returns true if the first object has at least the same
24
+ * entries as the second object
25
+ * @param superset - the object to check
26
+ * @param subset - the object whose entries are required
27
+ * @returns - true if the first object is a superset of the second
28
+ * @recursive
29
+ */
30
+ static isSuperset (superset: any, subset: any) : boolean {
31
+ let isSuperset: boolean = true;
32
+
33
+ // Base case - if the objects are equal, it is a superset
34
+ if (superset === subset) {
35
+ return isSuperset;
36
+ }
37
+
38
+ // If the subset isn't an object or array, and doesn't
39
+ // satisfy the base case, it isn't a superset
40
+ try {
41
+ if (Object.keys(subset).length === 0) {
42
+ return !isSuperset;
43
+ }
44
+ }
45
+ // If the subset is null or undefined, and doesn't satisfy
46
+ // the base case, it isn't a superset
47
+ // TODO: Check if other exceptions could occur
48
+ catch (e) {
49
+ return !isSuperset;
50
+ }
51
+
52
+ // If the children of the subset are subsets of the
53
+ // respective children of the superset, it is a superset
54
+ Object.keys(subset).forEach((key: string) => {
55
+ isSuperset = isSuperset && mintObject.isSuperset(superset[key], subset[key]);
56
+ });
57
+ return isSuperset;
58
+ };
59
+
60
+ /**
61
+ * Removes object entries by key
62
+ * @alias mintObject.removeKeys
63
+ * @param object - the object to remove entries from
64
+ * @param keys - the keys to remove
65
+ */
66
+ static remove (object: any, keys: string[]) : Object {
67
+ return this.removeKeys(object, keys);
68
+ };
69
+
70
+ /**
71
+ * Removes object entries by key
72
+ * @param object - the object to remove entries from
73
+ * @param keys - the keys to remove
74
+ */
75
+ static removeKeys (object: any, keys: string[]) : any {
76
+ return Object.keys(object).reduce((obj: any, key: string) => {
77
+ if (!keys.includes(key)) {
78
+ obj[key] = object[key];
79
+ }
80
+ return obj;
81
+ }, {});
82
+ };
83
+
84
+ /**
85
+ * Removes object entries by value
86
+ */
87
+ static removeValues (object: any, values: any[]) : any {
88
+ return Object.keys(object).reduce((obj: any, key: string) => {
89
+ if (!values.includes(object[key])) {
90
+ obj[key] = object[key];
91
+ }
92
+ return obj;
93
+ }, {});
94
+ };
95
+
96
+ /**
97
+ * Sorts an object's entries alphabetically by key
98
+ */
99
+ static sort (object: any) : Object {
100
+ return Object.keys(object).sort().reduce((obj: any, key: string) => {
101
+ obj[key] = object[key];
102
+ return obj;
103
+ }, {});
104
+ };
105
+
106
+ /**
107
+ * @alias mintObject.filterKeys
108
+ */
109
+ static filter (object: any, keys: string[]) : Object {
110
+ return this.filterKeys(object, keys);
111
+ };
112
+
113
+ /**
114
+ * Filters an object by its keys
115
+ * @param object - the object to filter
116
+ * @param keys - the keys to keep
117
+ * @returns - the filtered object
118
+ */
119
+ static filterKeys (object: any, keys: string[]) : Object {
120
+ return keys.reduce((obj: any, key: string) => {
121
+ obj[key] = object[key];
122
+ return obj;
123
+ }, {});
124
+ };
125
+
126
+ /**
127
+ * Filters an object by its values
128
+ * @param object - the object to filter
129
+ * @param values - the values to keep
130
+ * @returns - the filtered object
131
+ */
132
+ static filterValues (object: any, values: any[]) : Object {
133
+ return Object.keys(object).reduce((obj: any, key: string) => {
134
+ if (values.includes(object[key])) {
135
+ obj[key] = object[key];
136
+ }
137
+ return obj;
138
+ }, {});
139
+ };
140
+ };
141
+ export default mintObject;
@@ -0,0 +1,230 @@
1
+ /**
2
+ * CSS-selector helpers
3
+ * @public
4
+ */
5
+ export abstract class mintSelectors {
6
+ /**
7
+ * The library name that will be added as a prefix
8
+ */
9
+ static lib: string = 'mint';
10
+
11
+ /**
12
+ * The prefix built from the library name
13
+ */
14
+ static pre: string = `${this.lib}-`;
15
+
16
+ /**
17
+ * CSS-selector for disabled elements
18
+ */
19
+ static disabled: string = '[disabled]';
20
+
21
+ /**
22
+ * CSS-selector for elements with an aria-controls attribute
23
+ */
24
+ static hasControls: string = '[aria-controls]';
25
+
26
+ /**
27
+ * CSS-selector for elements with an aria-expanded attribute
28
+ */
29
+ static hasExpanded: string = '[aria-expanded]';
30
+
31
+ /**
32
+ * CSS-selector for elements with an href attribute
33
+ */
34
+ static hasLink: string = '[href]';
35
+
36
+ /**
37
+ * CSS-selector for elements with a routerLink attribute
38
+ */
39
+ static hasRouterLink: string = '[routerLink]';
40
+
41
+ /**
42
+ * CSS-selector for elements with an id attribute
43
+ */
44
+ static hasId: string = '[id]';
45
+
46
+ /**
47
+ * CSS-selector for elements that aren't tabbable (i.e. tabindex is negative)
48
+ */
49
+ static notTabbable: string = '[tabindex^="-"]';
50
+
51
+ /**
52
+ * CSS-selector for elements that are tabbable (i.e. tabindex isn't negative)
53
+ */
54
+ static tabbable: string = `[tabindex]${this.neg(this.notTabbable)}`;
55
+
56
+ /**
57
+ * CSS-selector for elements that can receive focus
58
+ */
59
+ static focusable: string = `input${this.neg(this.disabled)}${this.neg(this.notTabbable)},
60
+ select${this.neg(this.disabled)}${this.neg(this.notTabbable)},
61
+ textarea${this.neg(this.disabled)}${this.neg(this.notTabbable)},
62
+ button${this.neg(this.disabled)}${this.neg(this.notTabbable)},
63
+ object${this.neg(this.disabled)}${this.neg(this.notTabbable)},
64
+ a${this.hasLink}, a${this.hasRouterLink},
65
+ area${this.hasLink},
66
+ ${this.tabbable}`.replace(/\s/g, '');
67
+
68
+ /**
69
+ * CSS-selector for submenu buttons
70
+ */
71
+ static subMenuButtons: string = `button${this.hasControls}`;
72
+
73
+ /**
74
+ * CSS-selector for submenus
75
+ */
76
+ static subMenu: string = `${this.subMenuButtons} + ul${this.hasId}`;
77
+
78
+ /**
79
+ * Frequently-used ids
80
+ */
81
+ static ids: {[key: string]: string | {[key: string]: string}} = {
82
+ header: this.prefix('header'),
83
+ logo: this.prefix('logo'),
84
+ wrapper: this.prefix('wrapper'),
85
+ mainContent: this.prefix('main-content')
86
+ };
87
+
88
+ /**
89
+ * Classes
90
+ */
91
+ static classes: {[key: string]: string | {[key: string]: string}} = {
92
+ sides: {
93
+ top: this.prefix('top'),
94
+ right: this.prefix('right'),
95
+ bottom: this.prefix('bottom'),
96
+ left: this.prefix('left')
97
+ },
98
+ srOnly: this.prefix('sr-only'),
99
+ js: this.prefix('js'),
100
+ ready: this.prefix('ready'),
101
+ fixed: this.prefix('fixed'),
102
+ open: this.prefix('open')
103
+ };
104
+
105
+ /**
106
+ * Adds the library prefix to the beginning of the provided string
107
+ * @param base - the string to be prefixed
108
+ * @returns - the provided string prefixed with the library name
109
+ */
110
+ static prefix (base: string) : string {
111
+ base = base.toLowerCase();
112
+ return base.startsWith(this.pre) ? base : `${this.pre}${base}`;
113
+ }
114
+
115
+ /**
116
+ * Adds two dashes to the beginning of the provided string
117
+ * @param base - the string to be prefixed
118
+ * @returns - the provided string prefixed with two dashes
119
+ */
120
+ static cssPrefix (base: string) : string {
121
+ return `--${this.prefix(base.replace(/^-+/, ''))}`;
122
+ }
123
+
124
+ /**
125
+ * Turns the provided string into a CSS variable call
126
+ * @param base - the name of the CSS variable to call
127
+ * @returns - the CSS variable call for the provided string
128
+ */
129
+ static cssVar (base: string) : string {
130
+ return `var(${this.cssPrefix(base)})`;
131
+ }
132
+
133
+ /**
134
+ * Negates the provided CSS selector
135
+ * @param base - the CSS selector to negate
136
+ * @returns - the negated CSS selector
137
+ */
138
+ static neg (base: string) : string {
139
+ return `:not(${base})`;
140
+ }
141
+
142
+ /**
143
+ * Generates a class CSS selector
144
+ * @param base - the name of the class to generate
145
+ * @returns - the generated CSS selector
146
+ */
147
+ static class (base: string) : string {
148
+ return `.${this.prefix(base)}`;
149
+ }
150
+
151
+ /**
152
+ * Generates an id CSS selector
153
+ * @param base - the name of the id to generate
154
+ * @returns - the generated CSS selector
155
+ */
156
+ static id (base: string) : string {
157
+ return `#${this.prefix(base)}`;
158
+ }
159
+
160
+ /**
161
+ * Generates an aria-controls CSS selector
162
+ * @param id - the id of the controlled element
163
+ * @returns - the generated CSS selector
164
+ */
165
+ static controls (id?: string | null) : string {
166
+ return id ? `[aria-controls="${this.prefix(id)}"]` : this.hasControls;
167
+ }
168
+
169
+ /**
170
+ * Generates an aria-expanded CSS selector
171
+ * @param bool - whether the element is expanded or not
172
+ * @returns - the generated CSS selector
173
+ */
174
+ static expanded (bool?: boolean | null) : string {
175
+ return typeof bool === 'boolean' ? `[aria-expanded="${bool}"]` : this.hasExpanded;
176
+ }
177
+
178
+ /**
179
+ * Returns the id of the requested element
180
+ */
181
+ static getId (id?: string) : string {
182
+ return this.ids[id ?? -1] as string ?? '';
183
+ }
184
+
185
+ /**
186
+ * Returns the class of the requested element
187
+ */
188
+ static getClass (className?: string, classGroup?: string) : string {
189
+ if (classGroup) {
190
+ let group: {[key: string]: string} = this.classes[classGroup] as {[key: string]: string};
191
+ return group[className ?? -1] ?? '';
192
+ }
193
+ return this.classes[className ?? -1] as string ?? '';
194
+ }
195
+
196
+ /**
197
+ * Returns a NodeList of HTMLElements within the given element that are focusable
198
+ * @param el - the element whose focusable children will be returned
199
+ * @returns - the elements within the given element that are focusable
200
+ */
201
+ static getFocusables (el?: HTMLElement) : HTMLElement[] {
202
+ let focusables: HTMLElement[];
203
+ if (el) {
204
+ focusables = Array.from(el.querySelectorAll<HTMLElement>(this.focusable));
205
+ } else {
206
+ focusables = Array.from(document.querySelectorAll<HTMLElement>(this.focusable));
207
+ }
208
+ return focusables.filter((el: HTMLElement) => this.isFocusable(el));
209
+ }
210
+
211
+ /**
212
+ * Returns true if an element is focusable and false if not,
213
+ * based on styles (i.e. a parent has display: none;)
214
+ * NOTE: Still need to determine what other styles may make an element un-focusable
215
+ * @param el - the element
216
+ * @returns - true if the element is focusable; false if not
217
+ */
218
+ static isFocusable (el: HTMLElement) : boolean {
219
+ let current: HTMLElement | null = el;
220
+
221
+ do {
222
+ if (window.getComputedStyle(current).getPropertyValue('display').toLowerCase() === 'none') {
223
+ return false;
224
+ }
225
+ current = current.parentElement;
226
+ } while (current);
227
+ return true;
228
+ }
229
+ }
230
+ export default mintSelectors;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Imports
3
+ */
4
+ import { mintSide } from '../enum';
5
+ import { mintSelectors } from './selectors';
6
+
7
+ /**
8
+ * Settings management
9
+ * @public
10
+ */
11
+ export abstract class mintSettings {
12
+ /**
13
+ * Value added to all delay variables
14
+ */
15
+ static delayBase: number = 0;
16
+
17
+ /**
18
+ * Value multiplied by delay variable index
19
+ */
20
+ static delayStep: number = 100;
21
+
22
+ /**
23
+ * Delay variables
24
+ */
25
+ static delay: {[key: string]: number} = {
26
+ instant: this.delayBase + this.delayStep * 0,
27
+ fast: this.delayBase + this.delayStep * 1,
28
+ medFast: this.delayBase + this.delayStep * 2,
29
+ default: this.delayBase + this.delayStep * 3,
30
+ medSlow: this.delayBase + this.delayStep * 4,
31
+ slow: this.delayBase + this.delayStep * 5
32
+ };
33
+
34
+ /**
35
+ * Side of the window the mobile navbar enters from
36
+ */
37
+ static from?: mintSide;
38
+
39
+ /**
40
+ * Whether the navbar is fixed or not
41
+ */
42
+ static fixed?: boolean;
43
+
44
+ /**
45
+ * Update the provided settings variables
46
+ * @param settings - Object of settings variables to update
47
+ */
48
+ static set (settings: {[key: string]: any}) : void {
49
+ let newDelay: boolean = false;
50
+ if (typeof settings.delayBase === 'number') {
51
+ this.delayBase = settings.delayBase;
52
+ newDelay = true;
53
+ }
54
+ if (typeof settings.delayStep === 'number') {
55
+ this.delayStep = settings.delayStep;
56
+ newDelay = true;
57
+ }
58
+ if (newDelay) {
59
+ this.setDelay();
60
+ }
61
+
62
+ if (settings.delay && Object.keys(settings.delay).length) {
63
+ if (Object.values(settings.delay).reduce((prev: any, next: any) => prev && typeof next === 'number', true)) {
64
+ this.delay = {...this.delay, ...settings.delay};
65
+ }
66
+ }
67
+
68
+ if (typeof settings.from === 'number') {
69
+ this.setFrom(settings.from);
70
+ }
71
+
72
+ if (typeof settings.fixed === 'boolean') {
73
+ this.setFixed(settings.fixed);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Updates the delay variables based on `this.delayBase` and `this.delayStep`
79
+ */
80
+ protected static setDelay () : void {
81
+ this.delay = {
82
+ instant: this.delayBase + this.delayStep * 0,
83
+ fast: this.delayBase + this.delayStep * 1,
84
+ medFast: this.delayBase + this.delayStep * 2,
85
+ default: this.delayBase + this.delayStep * 3,
86
+ medSlow: this.delayBase + this.delayStep * 4,
87
+ slow: this.delayBase + this.delayStep * 5
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Updates the direction the navbar enters from
93
+ */
94
+ protected static setFrom (from: mintSide) : void {
95
+ if (this.from !== from) {
96
+ this.from = from;
97
+ let header: HTMLElement | null = document.getElementById(mintSelectors.getId('header'));
98
+ header?.classList.remove(...Object.values(mintSelectors.classes.sides));
99
+ header?.classList.add(mintSelectors.getClass(mintSide[this.from].toLowerCase(), 'sides'));
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Updates whether or not the navbar is fixed
105
+ */
106
+ protected static setFixed (fixed: boolean) : void {
107
+ if (this.fixed !== fixed) {
108
+ this.fixed = fixed;
109
+ let header: HTMLElement | null = document.getElementById(mintSelectors.getId('header')),
110
+ fixedClass: string = mintSelectors.getClass('fixed');
111
+ if (this.fixed) {
112
+ header?.classList.add(fixedClass);
113
+ } else {
114
+ header?.classList.remove(fixedClass);
115
+ }
116
+ }
117
+ }
118
+ };
119
+
120
+ export default mintSettings;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Functions for analyzing and manipulating text.
3
+ */
4
+ export abstract class mintText {
5
+ /*static fitContainer () {
6
+ let $warning: JQuery<HTMLElement> = $(warningSelector);
7
+ $warning.css({
8
+ overflow: 'scroll',
9
+ fontSize: ''
10
+ });
11
+ while (($warning?.[0].scrollHeight ?? Number.MIN_SAFE_INTEGER) > ($warning?.innerHeight() ?? Number.MAX_SAFE_INTEGER)) {
12
+ let fontSize: number = parseInt($warning.css('font-size')) - 1;
13
+ $warning.css('font-size', fontSize + 'px');
14
+ }
15
+ }*/
16
+
17
+ /**
18
+ * Generate a slug from a string
19
+ * @param str - The string to slugify
20
+ * @returns The slugified string
21
+ */
22
+ static slug (str: string): string {
23
+ return str.toLowerCase().replace(/\W+/g, '-').replace(/^-+|-+$/g, '');
24
+ }
25
+
26
+ /**
27
+ * Pluralize the given word
28
+ */
29
+ static pluralize (word: string): string {
30
+ if (word.endsWith('ies') ||
31
+ word.endsWith('es') ||
32
+ (word.endsWith('s') && !word.endsWith('us') && !word.endsWith('is') && !word.endsWith('ss'))) {
33
+ return word;
34
+ }
35
+
36
+ if (word.endsWith('y') && !['a', 'e', 'i', 'o', 'u'].includes(word.charAt(word.length - 2))) {
37
+ return word.slice(0, -1) + 'ies';
38
+ }
39
+
40
+ if (word.endsWith('s') || word.endsWith('sh') || word.endsWith('ch') || word.endsWith('x') || word.endsWith('z')) {
41
+ return word + 'es';
42
+ }
43
+
44
+ return word + 's';
45
+ }
46
+ };
47
+ export default mintText;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Functions related to the browser window.
3
+ */
4
+ export abstract class mintWindow {
5
+
6
+ };
7
+ export default mintWindow;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * A library for building responsive web applications.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+
7
+ /**
8
+ * Exports
9
+ */
10
+ // Enums
11
+ export { mintSide } from './imports/enum';
12
+
13
+ // Components
14
+ export { mintHeader } from './imports/components/header';
15
+
16
+ // Models
17
+ export { mintColor } from './imports/models/color';
18
+ export { mintItem } from './imports/models/item';
19
+
20
+ // Utilities
21
+ export { mintDisplay } from './imports/util/display';
22
+ export { mintEvent } from './imports/util/event';
23
+ export { mintIcon } from './imports/util/icon';
24
+ export { mintList } from './imports/util/list';
25
+ export { mintMath } from './imports/util/math';
26
+ export { mintObject } from './imports/util/object';
27
+ export { mintText } from './imports/util/text';
28
+ export { mintWindow } from './imports/util/window';
29
+
30
+ // Objects
31
+ export { mintSelectors } from './imports/util/selectors';
32
+ export { mintSettings } from './imports/util/settings';
33
+ export { mintUtil, default } from './util';