@stackoverflow/stacks 0.74.0 → 1.0.0-beta.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.
Files changed (89) hide show
  1. package/dist/controllers/index.d.ts +7 -0
  2. package/dist/controllers/s-expandable-control.d.ts +17 -0
  3. package/dist/controllers/s-modal.d.ts +97 -0
  4. package/dist/controllers/s-navigation-tablist.d.ts +36 -0
  5. package/dist/controllers/s-popover.d.ts +155 -0
  6. package/dist/controllers/s-table.d.ts +8 -0
  7. package/dist/controllers/s-tooltip.d.ts +82 -0
  8. package/dist/controllers/s-uploader.d.ts +48 -0
  9. package/dist/css/stacks.css +4633 -2703
  10. package/dist/css/stacks.min.css +1 -1
  11. package/dist/index.d.ts +3 -0
  12. package/dist/js/stacks.js +6026 -5403
  13. package/dist/js/stacks.min.js +1 -1
  14. package/dist/stacks.d.ts +21 -0
  15. package/lib/css/atomic/{_stacks-borders.less → borders.less} +30 -30
  16. package/lib/css/atomic/{_stacks-colors.less → colors.less} +0 -0
  17. package/lib/css/atomic/{_stacks-flex.less → flex.less} +14 -13
  18. package/lib/css/atomic/{_stacks-grid.less → grid.less} +12 -11
  19. package/lib/css/atomic/{_stacks-misc.less → misc.less} +23 -22
  20. package/lib/css/atomic/spacing.less +314 -0
  21. package/lib/css/atomic/{_stacks-typography.less → typography.less} +29 -29
  22. package/lib/css/atomic/width-height.less +194 -0
  23. package/lib/css/base/{_stacks-body.less → body.less} +3 -5
  24. package/lib/css/base/{_stacks-configuration-static.less → configuration-static.less} +3 -1
  25. package/lib/css/base/{_stacks-icons.less → icons.less} +0 -0
  26. package/lib/css/base/{_stacks-internals.less → internals.less} +0 -10
  27. package/lib/css/base/{_stacks-reset-meyer.less → reset-meyer.less} +0 -0
  28. package/lib/css/base/{_stacks-reset-normalize.less → reset-normalize.less} +0 -0
  29. package/lib/css/base/{_stacks-reset.less → reset.less} +2 -2
  30. package/lib/css/components/{_stacks-activity-indicator.less → activity-indicator.less} +9 -9
  31. package/lib/css/components/{_stacks-avatars.less → avatars.less} +40 -40
  32. package/lib/css/components/{_stacks-badges.less → badges.less} +11 -11
  33. package/lib/css/components/{_stacks-banners.less → banners.less} +5 -6
  34. package/lib/css/components/{_stacks-blank-states.less → blank-states.less} +2 -2
  35. package/lib/css/components/{_stacks-breadcrumbs.less → breadcrumbs.less} +7 -7
  36. package/lib/css/components/{_stacks-button-groups.less → button-groups.less} +2 -2
  37. package/lib/css/components/{_stacks-buttons.less → buttons.less} +77 -72
  38. package/lib/css/components/{_stacks-cards.less → cards.less} +2 -2
  39. package/lib/css/components/{_stacks-code-blocks.less → code-blocks.less} +8 -8
  40. package/lib/css/components/{_stacks-collapsible.less → collapsible.less} +0 -0
  41. package/lib/css/components/{_stacks-inputs.less → inputs.less} +41 -41
  42. package/lib/css/components/{_stacks-link-previews.less → link-previews.less} +17 -17
  43. package/lib/css/components/{_stacks-links.less → links.less} +4 -4
  44. package/lib/css/components/{_stacks-menu.less → menu.less} +5 -5
  45. package/lib/css/components/{_stacks-modals.less → modals.less} +20 -20
  46. package/lib/css/components/{_stacks-navigation.less → navigation.less} +12 -12
  47. package/lib/css/components/{_stacks-notices.less → notices.less} +12 -12
  48. package/lib/css/components/{_stacks-page-titles.less → page-titles.less} +9 -9
  49. package/lib/css/components/{_stacks-pagination.less → pagination.less} +8 -8
  50. package/lib/css/components/{_stacks-popovers.less → popovers.less} +17 -17
  51. package/lib/css/components/{_stacks-post-summary.less → post-summary.less} +155 -60
  52. package/lib/css/components/{_stacks-progress-bars.less → progress-bars.less} +29 -30
  53. package/lib/css/components/{_stacks-prose.less → prose.less} +31 -31
  54. package/lib/css/components/{_stacks-spinner.less → spinner.less} +14 -14
  55. package/lib/css/components/{_stacks-tables.less → tables.less} +10 -10
  56. package/lib/css/components/{_stacks-tags.less → tags.less} +33 -41
  57. package/lib/css/components/{_stacks-toggle-switches.less → toggle-switches.less} +5 -5
  58. package/lib/css/components/{_stacks-topbar.less → topbar.less} +27 -40
  59. package/lib/css/components/{_stacks-uploader.less → uploader.less} +18 -18
  60. package/lib/css/components/{_stacks-user-cards.less → user-cards.less} +14 -14
  61. package/lib/css/components/{_stacks-widget-dynamic.less → widget-dynamic.less} +1 -1
  62. package/lib/css/components/{_stacks-widget-static.less → widget-static.less} +39 -38
  63. package/lib/css/exports/{_stacks-constants-colors.less → constants-colors.less} +21 -29
  64. package/lib/css/exports/constants-helpers.less +108 -0
  65. package/lib/css/exports/constants-type.less +153 -0
  66. package/lib/css/exports/{_stacks-exports.less → exports.less} +4 -4
  67. package/lib/css/exports/{_stacks-mixins.less → mixins.less} +18 -1
  68. package/lib/css/stacks-dynamic.less +12 -13
  69. package/lib/css/stacks-static.less +38 -38
  70. package/lib/ts/controllers/index.ts +8 -0
  71. package/lib/ts/controllers/s-expandable-control.ts +163 -164
  72. package/lib/ts/controllers/s-modal.ts +259 -261
  73. package/lib/ts/controllers/s-navigation-tablist.ts +96 -97
  74. package/lib/ts/controllers/s-popover.ts +438 -440
  75. package/lib/ts/controllers/s-table.ts +203 -203
  76. package/lib/ts/controllers/s-tooltip.ts +195 -196
  77. package/lib/ts/controllers/s-uploader.ts +162 -164
  78. package/lib/ts/index.ts +20 -0
  79. package/lib/ts/stacks.ts +73 -68
  80. package/lib/tsconfig.json +8 -6
  81. package/package.json +43 -27
  82. package/dist/css/stacks-flexgrid-shim.min.css +0 -1
  83. package/lib/css/atomic/_stacks-spacing.less +0 -162
  84. package/lib/css/atomic/_stacks-width-height.less +0 -189
  85. package/lib/css/base/_stacks-configuration-dynamic.less +0 -106
  86. package/lib/css/exports/_stacks-constants-helpers.less +0 -139
  87. package/lib/css/exports/_stacks-constants-type.less +0 -91
  88. package/lib/ts/finalize.ts +0 -1
  89. package/lib/ts/stimulus.d.ts +0 -4
@@ -1,174 +1,172 @@
1
- namespace Stacks {
2
- interface FilePreview {
3
- data?: string | ArrayBuffer;
4
- name: string;
5
- type: string;
6
- };
7
-
8
- export class UploaderController extends Stacks.StacksController {
9
- static targets = ["input", "previews", "uploader"];
10
- private inputTarget!: HTMLInputElement;
11
- private previewsTarget!: HTMLElement;
12
- private uploaderTarget!: HTMLElement;
13
-
14
- private boundDragEnter!: any;
15
- private boundDragLeave!: any;
16
-
17
- private static readonly FILE_DISPLAY_LIMIT = 10;
18
- private static readonly MAX_FILE_SIZE = 1024 * 1024 * 10; // 10 MB
19
-
20
- connect() {
21
- super.connect();
22
- this.boundDragEnter = this.handleUploaderActive.bind(this, true);
23
- this.boundDragLeave = this.handleUploaderActive.bind(this, false);
24
-
25
- this.inputTarget.addEventListener("dragenter", this.boundDragEnter);
26
- this.inputTarget.addEventListener("dragleave", this.boundDragLeave);
1
+ import * as Stacks from "../stacks";
2
+
3
+ interface FilePreview {
4
+ data?: string | ArrayBuffer;
5
+ name: string;
6
+ type: string;
7
+ };
8
+
9
+ export class UploaderController extends Stacks.StacksController {
10
+ static targets = ["input", "previews", "uploader"];
11
+ private inputTarget!: HTMLInputElement;
12
+ private previewsTarget!: HTMLElement;
13
+ private uploaderTarget!: HTMLElement;
14
+
15
+ private boundDragEnter!: any;
16
+ private boundDragLeave!: any;
17
+
18
+ private static readonly FILE_DISPLAY_LIMIT = 10;
19
+ private static readonly MAX_FILE_SIZE = 1024 * 1024 * 10; // 10 MB
20
+
21
+ connect() {
22
+ super.connect();
23
+ this.boundDragEnter = this.handleUploaderActive.bind(this, true);
24
+ this.boundDragLeave = this.handleUploaderActive.bind(this, false);
25
+
26
+ this.inputTarget.addEventListener("dragenter", this.boundDragEnter);
27
+ this.inputTarget.addEventListener("dragleave", this.boundDragLeave);
28
+ }
29
+
30
+ disconnect() {
31
+ this.inputTarget.removeEventListener("dragenter", this.boundDragEnter);
32
+ this.inputTarget.removeEventListener("dragleave", this.boundDragLeave);
33
+ super.disconnect();
34
+ }
35
+
36
+ /**
37
+ * Handles rendering the file preview state on input change
38
+ */
39
+ handleInput() {
40
+ this.previewsTarget.innerHTML = "";
41
+
42
+ if (!this.inputTarget.files) {
43
+ return;
27
44
  }
28
45
 
29
- disconnect() {
30
- this.inputTarget.removeEventListener("dragenter", this.boundDragEnter);
31
- this.inputTarget.removeEventListener("dragleave", this.boundDragLeave);
32
- super.disconnect();
33
- }
34
-
35
- /**
36
- * Handles rendering the file preview state on input change
37
- */
38
- handleInput() {
39
- this.previewsTarget.innerHTML = "";
40
-
41
- if (!this.inputTarget.files) {
42
- return;
43
- }
44
-
45
- const count = this.inputTarget.files.length;
46
- this.getDataURLs(this.inputTarget.files, UploaderController.FILE_DISPLAY_LIMIT)
47
- .then((res: FilePreview[]) => {
48
- this.handleVisible(true);
49
- const hasMultipleFiles = res.length > 1;
50
-
51
- if (hasMultipleFiles) {
52
- let headingElement = document.createElement("div");
53
- headingElement.classList.add("s-uploader--previews-heading");
54
- headingElement.innerText = res.length < count ?
55
- `Showing ${res.length} of ${count} files` : `${count} items`;
56
- this.previewsTarget.appendChild(headingElement);
57
- this.previewsTarget.classList.add("has-multiple");
58
- } else {
59
- this.previewsTarget.classList.remove("has-multiple");
60
- }
61
- res.forEach((file) => this.addFilePreview(file));
62
- this.handleUploaderActive(true);
63
- });
64
- }
65
-
66
- /**
67
- * Resets the Uploader to initial state
68
- */
69
- reset() {
70
- this.inputTarget.value = '';
71
- this.previewsTarget.innerHTML = "";
72
- this.handleVisible(false);
46
+ const count = this.inputTarget.files.length;
47
+ this.getDataURLs(this.inputTarget.files, UploaderController.FILE_DISPLAY_LIMIT)
48
+ .then((res: FilePreview[]) => {
49
+ this.handleVisible(true);
50
+ const hasMultipleFiles = res.length > 1;
51
+
52
+ if (hasMultipleFiles) {
53
+ let headingElement = document.createElement("div");
54
+ headingElement.classList.add("s-uploader--previews-heading");
55
+ headingElement.innerText = res.length < count ?
56
+ `Showing ${res.length} of ${count} files` : `${count} items`;
57
+ this.previewsTarget.appendChild(headingElement);
58
+ this.previewsTarget.classList.add("has-multiple");
59
+ } else {
60
+ this.previewsTarget.classList.remove("has-multiple");
61
+ }
62
+ res.forEach((file) => this.addFilePreview(file));
63
+ this.handleUploaderActive(true);
64
+ });
65
+ }
66
+
67
+ /**
68
+ * Resets the Uploader to initial state
69
+ */
70
+ reset() {
71
+ this.inputTarget.value = '';
72
+ this.previewsTarget.innerHTML = "";
73
+ this.handleVisible(false);
74
+ }
75
+
76
+ /**
77
+ * Set hide/show and disabled state on elements depending on preview state
78
+ * @param {boolean} shouldPreview - Uploader is entering a preview state
79
+ */
80
+ private handleVisible(shouldPreview: boolean) {
81
+ const { scope } = this.targets;
82
+ const hideElements = scope.findAllElements('[data-s-uploader-hide-on-input]');
83
+ const showElements = scope.findAllElements('[data-s-uploader-show-on-input]');
84
+ const enableElements = scope.findAllElements('[data-s-uploader-enable-on-input]');
85
+
86
+ if (shouldPreview) {
87
+ hideElements.map(el => el.classList.add("d-none"));
88
+ showElements.map(el => el.classList.remove("d-none"));
89
+ enableElements.map(el => el.removeAttribute("disabled"));
90
+ } else {
91
+ hideElements.map(el => el.classList.remove("d-none"));
92
+ showElements.map(el => el.classList.add("d-none"));
93
+ enableElements.map(el => el.setAttribute("disabled", "true"))
94
+ this.handleUploaderActive(false);
73
95
  }
74
-
75
- /**
76
- * Set hide/show and disabled state on elements depending on preview state
77
- * @param {boolean} shouldPreview - Uploader is entering a preview state
78
- */
79
- private handleVisible(shouldPreview: boolean) {
80
- const { scope } = this.targets;
81
- const hideElements = scope.findAllElements('[data-s-uploader-hide-on-input]');
82
- const showElements = scope.findAllElements('[data-s-uploader-show-on-input]');
83
- const enableElements = scope.findAllElements('[data-s-uploader-enable-on-input]');
84
-
85
- if (shouldPreview) {
86
- hideElements.map(el => el.classList.add("d-none"));
87
- showElements.map(el => el.classList.remove("d-none"));
88
- enableElements.map(el => el.removeAttribute("disabled"));
89
- } else {
90
- hideElements.map(el => el.classList.remove("d-none"));
91
- showElements.map(el => el.classList.add("d-none"));
92
- enableElements.map(el => el.setAttribute("disabled", "true"))
93
- this.handleUploaderActive(false);
94
- }
96
+ }
97
+
98
+ /**
99
+ * Adds a DOM element to preview a selected file
100
+ * @param {FilePreview} file
101
+ */
102
+ private addFilePreview(file: FilePreview) {
103
+ if (!file) {
104
+ return;
95
105
  }
96
106
 
97
- /**
98
- * Adds a DOM element to preview a selected file
99
- * @param {FilePreview} file
100
- */
101
- private addFilePreview(file: FilePreview) {
102
- if (!file) {
103
- return;
104
- }
105
-
106
- let previewElement = document.createElement("div");
107
- let thumbElement;
108
-
109
- if (file.type.match('image/*') && file.data) {
110
- thumbElement = document.createElement("img");
111
- thumbElement.src = file.data.toString();
112
- thumbElement.alt = file.name;
113
- } else {
114
- thumbElement = document.createElement("div");
115
- thumbElement.innerText = file.name;
116
- }
117
-
118
- thumbElement.classList.add("s-uploader--preview-thumbnail");
119
- previewElement.appendChild(thumbElement);
120
- previewElement.classList.add("s-uploader--preview");
121
- previewElement.setAttribute('data-filename', file.name);
122
- this.previewsTarget.appendChild(previewElement);
123
- }
107
+ let previewElement = document.createElement("div");
108
+ let thumbElement;
124
109
 
125
- /**
126
- * Toggles display and disabled state for select elements on valid input
127
- * @param {boolean} active - Uploader is in active state (typically on 'dragenter')
128
- */
129
- private handleUploaderActive(active: boolean) {
130
- this.uploaderTarget.classList.toggle("is-active", active);
110
+ if (file.type.match('image/*') && file.data) {
111
+ thumbElement = document.createElement("img");
112
+ thumbElement.src = file.data.toString();
113
+ thumbElement.alt = file.name;
114
+ } else {
115
+ thumbElement = document.createElement("div");
116
+ thumbElement.innerText = file.name;
131
117
  }
132
118
 
133
- /**
134
- * Converts the file data into a data URL
135
- * @param {File} file
136
- * @returns an object containing a FilePreview object
137
- */
138
- private fileToDataURL(file: File): Promise<FilePreview> {
139
- var reader = new FileReader();
140
- const { name, size, type } = file;
141
-
142
- if (size < UploaderController.MAX_FILE_SIZE && type.indexOf("image") > -1) {
143
- return new Promise((resolve, reject) => {
144
- reader.onload = evt => {
145
- const res = evt?.target?.result;
146
- if (res) {
147
- resolve({ data: res, name, type });
148
- } else {
149
- reject();
150
- }
119
+ thumbElement.classList.add("s-uploader--preview-thumbnail");
120
+ previewElement.appendChild(thumbElement);
121
+ previewElement.classList.add("s-uploader--preview");
122
+ previewElement.setAttribute('data-filename', file.name);
123
+ this.previewsTarget.appendChild(previewElement);
124
+ }
125
+
126
+ /**
127
+ * Toggles display and disabled state for select elements on valid input
128
+ * @param {boolean} active - Uploader is in active state (typically on 'dragenter')
129
+ */
130
+ private handleUploaderActive(active: boolean) {
131
+ this.uploaderTarget.classList.toggle("is-active", active);
132
+ }
133
+
134
+ /**
135
+ * Converts the file data into a data URL
136
+ * @param {File} file
137
+ * @returns an object containing a FilePreview object
138
+ */
139
+ private fileToDataURL(file: File): Promise<FilePreview> {
140
+ var reader = new FileReader();
141
+ const { name, size, type } = file;
142
+
143
+ if (size < UploaderController.MAX_FILE_SIZE && type.indexOf("image") > -1) {
144
+ return new Promise((resolve, reject) => {
145
+ reader.onload = evt => {
146
+ const res = evt?.target?.result;
147
+ if (res) {
148
+ resolve({ data: res, name, type });
149
+ } else {
150
+ reject();
151
151
  }
152
- reader.readAsDataURL(file);
153
- });
154
- } else {
155
- return Promise.resolve({ name, type });
156
- }
152
+ }
153
+ reader.readAsDataURL(file);
154
+ });
155
+ } else {
156
+ return Promise.resolve({ name, type });
157
157
  }
158
-
159
- /**
160
- * Gets an array of FilePreviews from a FileList
161
- * @param {FileList|[]} files
162
- * @returns an array of FilePreview objects from a FileList
163
- */
164
- private getDataURLs(files: FileList, limit: number): Promise<FilePreview[]> {
165
- const promises = Array.from(files)
166
- .slice(0, Math.min(limit, files.length))
167
- .map(f => this.fileToDataURL(f));
168
-
169
- return Promise.all(promises);
170
- }
171
- };
172
- }
173
-
174
- Stacks.application.register("s-uploader", Stacks.UploaderController);
158
+ }
159
+
160
+ /**
161
+ * Gets an array of FilePreviews from a FileList
162
+ * @param {FileList|[]} files
163
+ * @returns an array of FilePreview objects from a FileList
164
+ */
165
+ private getDataURLs(files: FileList, limit: number): Promise<FilePreview[]> {
166
+ const promises = Array.from(files)
167
+ .slice(0, Math.min(limit, files.length))
168
+ .map(f => this.fileToDataURL(f));
169
+
170
+ return Promise.all(promises);
171
+ }
172
+ };
@@ -0,0 +1,20 @@
1
+ import '../css/stacks.less';
2
+ import { ExpandableController, ModalController, PopoverController, TableController, TabListController, TooltipController, UploaderController } from './controllers';
3
+ import { application, StacksApplication } from './stacks';
4
+
5
+ // register all built-in controllers
6
+ application.register("s-expandable-control", ExpandableController);
7
+ application.register("s-modal", ModalController);
8
+ application.register("s-navigation-tablist", TabListController);
9
+ application.register("s-popover", PopoverController);
10
+ application.register("s-table", TableController);
11
+ application.register("s-tooltip", TooltipController);
12
+ application.register("s-uploader", UploaderController);
13
+
14
+ // finalize the application to guard our controller namespace
15
+ StacksApplication.finalize();
16
+
17
+ // export all controllers w/ helpers
18
+ export * from "./controllers";
19
+ // export the entirety of the contents of stacks.ts
20
+ export * from "./stacks";
package/lib/ts/stacks.ts CHANGED
@@ -1,83 +1,88 @@
1
- namespace Stacks {
2
- class StacksApplication extends Stimulus.Application {
3
- load(...definitions: Stimulus.Definition[]): void
4
- load(definitions: Stimulus.Definition[]): void
5
- load(head: Stimulus.Definition | Stimulus.Definition[], ...rest: Stimulus.Definition[]) {
6
- const definitions = Array.isArray(head) ? head : [head, ...rest];
1
+ import * as Stimulus from "stimulus";
7
2
 
8
- for (const definition of definitions) {
9
- var hasPrefix = /^s-/.test(definition.identifier);
10
- if (_initializing && !hasPrefix) {
11
- throw "Stacks-created Stimulus controller names must start with \"s-\".";
12
- }
13
- if (!_initializing && hasPrefix) {
14
- throw "The \"s-\" prefix on Stimulus controller names is reserved for Stacks-created controllers.";
15
- }
3
+ export class StacksApplication extends Stimulus.Application {
4
+ static _initializing = true;
5
+
6
+ load(...definitions: Stimulus.Definition[]): void
7
+ load(definitions: Stimulus.Definition[]): void
8
+ load(head: Stimulus.Definition | Stimulus.Definition[], ...rest: Stimulus.Definition[]) {
9
+ const definitions = Array.isArray(head) ? head : [head, ...rest];
10
+
11
+ for (const definition of definitions) {
12
+ var hasPrefix = /^s-/.test(definition.identifier);
13
+ if (StacksApplication._initializing && !hasPrefix) {
14
+ throw "Stacks-created Stimulus controller names must start with \"s-\".";
15
+ }
16
+ if (!StacksApplication._initializing && hasPrefix) {
17
+ throw "The \"s-\" prefix on Stimulus controller names is reserved for Stacks-created controllers.";
16
18
  }
17
-
18
- super.load(definitions);
19
19
  }
20
20
 
21
- static start(element?: Element, schema?: Stimulus.Schema): StacksApplication {
22
- const application = new StacksApplication(element, schema);
23
- application.start();
24
- return application;
25
- }
21
+ super.load(definitions);
26
22
  }
27
23
 
28
- export const application: Stimulus.Application = StacksApplication.start();
29
- export var _initializing = true;
30
-
31
- export class StacksController extends Stimulus.Controller {
32
- protected getElementData(element: Element, key: string) {
33
- return element.getAttribute("data-" + this.identifier + "-" + key);
34
- };
35
- protected setElementData(element: Element, key: string, value: string) {
36
- element.setAttribute("data-" + this.identifier + "-" + key, value);
37
- };
38
- protected removeElementData(element: Element, key: string) {
39
- element.removeAttribute("data-" + this.identifier + "-" + key);
40
- };
41
- protected triggerEvent<T>(eventName: string, detail?: T, optionalElement?: Element) {
42
- const namespacedName = this.identifier + ":" + eventName;
43
- var event : CustomEvent<T>;
44
- try {
45
- event = new CustomEvent(namespacedName, {bubbles: true, cancelable: true, detail: detail});
46
- } catch (ex) {
47
- // Internet Explorer
48
- event = document.createEvent("CustomEvent");
49
- event.initCustomEvent(namespacedName, true, true, detail!);
50
- }
51
- (optionalElement || this.element).dispatchEvent(event);
52
- return event;
53
- };
24
+ static start(element?: Element, schema?: Stimulus.Schema): StacksApplication {
25
+ const application = new StacksApplication(element, schema);
26
+ application.start();
27
+ return application;
54
28
  }
55
29
 
56
- // ControllerDefinition/createController/addController is here to make
57
- // it easier to consume Stimulus from ES5 files (without classes)
58
- export interface ControllerDefinition {
59
- [name: string]: any;
60
- targets?: string[];
30
+ static finalize() {
31
+ StacksApplication._initializing = false;
61
32
  }
62
- export function createController(controllerDefinition: ControllerDefinition): typeof StacksController {
63
- const Controller = controllerDefinition.hasOwnProperty("targets")
64
- ? class Controller extends StacksController { static targets = controllerDefinition.targets! }
65
- : class Controller extends StacksController {};
33
+ }
66
34
 
67
- for (var prop in controllerDefinition) {
68
- if (prop !== "targets" && controllerDefinition.hasOwnProperty(prop)) {
69
- Object.defineProperty(
70
- Controller.prototype,
71
- prop,
72
- Object.getOwnPropertyDescriptor(controllerDefinition, prop)!
73
- );
74
- }
35
+ export const application: Stimulus.Application = StacksApplication.start();
36
+
37
+ export class StacksController extends Stimulus.Controller {
38
+ protected getElementData(element: Element, key: string) {
39
+ return element.getAttribute("data-" + this.identifier + "-" + key);
40
+ };
41
+ protected setElementData(element: Element, key: string, value: string) {
42
+ element.setAttribute("data-" + this.identifier + "-" + key, value);
43
+ };
44
+ protected removeElementData(element: Element, key: string) {
45
+ element.removeAttribute("data-" + this.identifier + "-" + key);
46
+ };
47
+ protected triggerEvent<T>(eventName: string, detail?: T, optionalElement?: Element) {
48
+ const namespacedName = this.identifier + ":" + eventName;
49
+ var event : CustomEvent<T>;
50
+ try {
51
+ event = new CustomEvent(namespacedName, {bubbles: true, cancelable: true, detail: detail});
52
+ } catch (ex) {
53
+ // Internet Explorer
54
+ event = document.createEvent("CustomEvent");
55
+ event.initCustomEvent(namespacedName, true, true, detail!);
75
56
  }
57
+ (optionalElement || this.element).dispatchEvent(event);
58
+ return event;
59
+ };
60
+ }
76
61
 
77
- return Controller;
78
- }
62
+ // ControllerDefinition/createController/addController is here to make
63
+ // it easier to consume Stimulus from ES5 files (without classes)
64
+ export interface ControllerDefinition {
65
+ [name: string]: any;
66
+ targets?: string[];
67
+ }
68
+ export function createController(controllerDefinition: ControllerDefinition): typeof StacksController {
69
+ const Controller = controllerDefinition.hasOwnProperty("targets")
70
+ ? class Controller extends StacksController { static targets = controllerDefinition.targets! }
71
+ : class Controller extends StacksController {};
79
72
 
80
- export function addController(name: string, controller: ControllerDefinition) {
81
- application.register(name, createController(controller));
73
+ for (var prop in controllerDefinition) {
74
+ if (prop !== "targets" && controllerDefinition.hasOwnProperty(prop)) {
75
+ Object.defineProperty(
76
+ Controller.prototype,
77
+ prop,
78
+ Object.getOwnPropertyDescriptor(controllerDefinition, prop)!
79
+ );
80
+ }
82
81
  }
82
+
83
+ return Controller;
84
+ }
85
+
86
+ export function addController(name: string, controller: ControllerDefinition) {
87
+ application.register(name, createController(controller));
83
88
  }
package/lib/tsconfig.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "strict": true,
4
- "typeRoots": ["../node_modules/@types", "../node_modules/@stimulus/core/src"],
5
4
  "target": "es5",
6
- "lib": ["dom", "es6", "dom.iterable", "scripthost"], // es6 stuff is polyfilled by stimulus
7
- "outDir": "../build",
8
- "rootDir": "."
5
+ "lib": ["dom", "es6", "dom.iterable", "scripthost"], // es6 stuff is polyfilled by stimulus
6
+ "outDir": "../dist",
7
+ "sourceMap": true,
8
+ "moduleResolution": "node",
9
+ "skipLibCheck": true,
10
+ "declaration": true
9
11
  },
10
- "include": ["./ts/**/*.ts"]
11
- }
12
+ "include": ["ts/**/*"]
13
+ }
package/package.json CHANGED
@@ -5,53 +5,69 @@
5
5
  "type": "git",
6
6
  "url": "https://github.com/StackExchange/Stacks.git"
7
7
  },
8
- "version": "0.74.0",
8
+ "version": "1.0.0-beta.0",
9
9
  "files": [
10
10
  "dist",
11
11
  "lib"
12
12
  ],
13
+ "main": "./dist/js/stacks.js",
14
+ "types": "./dist/index.d.ts",
15
+ "style": "./dist/css/stacks.css",
16
+ "less": "./lib/css/stacks.less",
13
17
  "unpkg": "dist/css/stacks.min.css",
14
18
  "scripts": {
15
- "start": "grunt",
16
- "build": "grunt build",
19
+ "start": "concurrently -n w: npm:start:*",
20
+ "build": "concurrently -n w: npm:build:*",
21
+ "build:bundle": "webpack --mode=production",
22
+ "build:docs": "webpack --mode=production --config ./docs/webpack.config.js && cd ./docs && eleventy",
23
+ "start:webpack": "webpack --watch --config ./docs/webpack.config.js",
24
+ "start:eleventy": "cd ./docs && eleventy --serve",
17
25
  "test": "backstop test",
18
- "approve": "backstop approve"
26
+ "approve": "backstop approve",
27
+ "prepublishOnly": "npm run build",
28
+ "lint:eslint": "eslint .",
29
+ "lint:prettier": "prettier --check . --end-of-line auto"
19
30
  },
20
31
  "license": "MIT",
21
32
  "dependencies": {
22
- "@popperjs/core": "^2.11.2",
33
+ "@popperjs/core": "^2.11.4",
23
34
  "stimulus": "^2.0.0"
24
35
  },
25
36
  "devDependencies": {
26
- "@11ty/eleventy": "^0.12.1",
27
- "@highlightjs/cdn-assets": "^11.4.0",
28
- "@stackoverflow/stacks-editor": "^0.4.1",
29
- "@stackoverflow/stacks-icons": "^2.26.0",
37
+ "@11ty/eleventy": "^1.0.0",
38
+ "@highlightjs/cdn-assets": "^11.5.0",
39
+ "@stackoverflow/stacks-editor": "^0.4.2",
40
+ "@stackoverflow/stacks-icons": "^2.27.0",
41
+ "@typescript-eslint/eslint-plugin": "^5.17.0",
42
+ "@typescript-eslint/parser": "^5.17.0",
30
43
  "backstopjs": "^6.0.4",
44
+ "concurrently": "^7.1.0",
45
+ "css-loader": "^6.7.1",
46
+ "cssnano": "^5.1.7",
31
47
  "docsearch.js": "^2.6.3",
32
- "eleventy-plugin-highlightjs": "^0.3.0",
33
- "eleventy-plugin-markdown-shortcode": "^1.1.0",
48
+ "eleventy-plugin-highlightjs": "^1.0.0",
34
49
  "eleventy-plugin-nesting-toc": "^1.3.0",
35
- "grunt": "^1.4.1",
36
- "grunt-cli": "^1.4.3",
50
+ "eslint": "^8.12.0",
51
+ "eslint-config-prettier": "^8.5.0",
52
+ "eslint-plugin-no-unsanitized": "^4.0.1",
37
53
  "grunt-concurrent": "^3.0.0",
38
- "grunt-contrib-clean": "^2.0.0",
39
- "grunt-contrib-concat": "^2.0.0",
40
- "grunt-contrib-copy": "^1.0.0",
41
- "grunt-contrib-cssmin": "^4.0.0",
42
- "grunt-contrib-less": "^3.0.0",
43
- "grunt-contrib-uglify": "^5.0.1",
44
- "grunt-contrib-watch": "^1.1.0",
45
- "grunt-shell": "^3.0.1",
46
- "grunt-ts": "^6.0.0-beta.22",
47
54
  "jquery": "^3.6.0",
55
+ "less-loader": "^10.2.0",
48
56
  "list.js": "^2.3.1",
57
+ "markdown-it": "^12.3.2",
58
+ "mini-css-extract-plugin": "^2.6.0",
49
59
  "postcss-less": "^6.0.0",
50
- "stylelint": "^14.3.0",
51
- "stylelint-config-recommended-less": "^1.0.1",
52
- "stylelint-config-standard": "^24.0.0",
53
- "stylelint-less": "^1.0.1",
54
- "typescript": "^4.5.5"
60
+ "postcss-loader": "^6.2.1",
61
+ "prettier": "^2.6.2",
62
+ "stylelint": "^14.6.1",
63
+ "stylelint-config-recommended": "^7.0.0",
64
+ "stylelint-config-standard": "^25.0.0",
65
+ "terser-webpack-plugin": "^5.3.1",
66
+ "ts-loader": "^9.2.8",
67
+ "typescript": "^4.6.3",
68
+ "webpack": "^5.71.0",
69
+ "webpack-cli": "^4.9.2",
70
+ "webpack-merge": "^5.8.0"
55
71
  },
56
72
  "browserslist": [
57
73
  "last 2 versions",