pinstripe 0.22.0 → 0.24.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 (152) hide show
  1. package/README.md +10 -0
  2. package/cli.js +46 -0
  3. package/lib/app.js +35 -0
  4. package/lib/apps/_file_importer.js +1 -0
  5. package/lib/apps/docs.js +6 -0
  6. package/lib/apps/main.js +6 -0
  7. package/lib/class.js +64 -0
  8. package/lib/client.js +20 -0
  9. package/lib/command.js +41 -0
  10. package/lib/commands/_file_importer.js +1 -0
  11. package/lib/commands/drop_database.js +6 -0
  12. package/lib/commands/generate_app.js +41 -0
  13. package/lib/commands/generate_command.js +39 -0
  14. package/lib/commands/generate_component.js +51 -0
  15. package/lib/commands/generate_migration.js +55 -0
  16. package/lib/commands/generate_model.js +43 -0
  17. package/lib/commands/generate_project.js +133 -0
  18. package/lib/commands/generate_service.js +32 -0
  19. package/lib/commands/generate_static_site.js +74 -0
  20. package/lib/commands/generate_view.js +44 -0
  21. package/lib/commands/init_database.js +9 -0
  22. package/lib/commands/list_apps.js +15 -0
  23. package/lib/commands/list_commands.js +15 -0
  24. package/lib/commands/list_components.js +16 -0
  25. package/lib/commands/list_migrations.js +15 -0
  26. package/lib/commands/list_models.js +15 -0
  27. package/lib/commands/list_services.js +15 -0
  28. package/lib/commands/list_views.js +39 -0
  29. package/lib/commands/migrate_database.js +6 -0
  30. package/lib/commands/purge_old_sessions.js +12 -0
  31. package/lib/commands/reset_database.js +9 -0
  32. package/lib/commands/seed_database.js +6 -0
  33. package/lib/commands/show_config.js +6 -0
  34. package/lib/commands/start_repl.js +6 -0
  35. package/lib/commands/start_server.js +31 -0
  36. package/lib/component.js +86 -34
  37. package/lib/component_event.js +28 -0
  38. package/lib/components/_file_importer.js +1 -0
  39. package/lib/components/a.js +27 -0
  40. package/lib/components/body.js +2 -4
  41. package/lib/components/document.js +18 -11
  42. package/lib/components/form.js +2 -4
  43. package/lib/components/helpers.js +11 -14
  44. package/lib/components/pinstripe_frame.js +60 -0
  45. package/lib/components/{markdown_editor.js → pinstripe_markdown_editor.js} +7 -8
  46. package/lib/components/pinstripe_modal.js +77 -0
  47. package/lib/components/{overlay.js → pinstripe_overlay.js} +11 -18
  48. package/lib/components/{progress_bar.js → pinstripe_progress_bar.js} +2 -4
  49. package/lib/components/pinstripe_silo.js +2 -0
  50. package/lib/components/pinstripe_skeleton.js +55 -0
  51. package/lib/components/script.js +11 -0
  52. package/lib/constants.js +26 -0
  53. package/lib/context.js +40 -0
  54. package/lib/database/client.js +242 -0
  55. package/lib/database/column_reference.js +13 -0
  56. package/lib/database/constants.js +87 -0
  57. package/lib/database/index.js +7 -0
  58. package/lib/database/migration.js +30 -0
  59. package/lib/database/migrator.js +28 -0
  60. package/lib/database/row.js +390 -0
  61. package/lib/database/singleton.js +12 -0
  62. package/lib/database/table.js +516 -0
  63. package/lib/database/table_reference.js +33 -0
  64. package/lib/database/union.js +128 -0
  65. package/lib/database.js +139 -0
  66. package/lib/defer.js +35 -0
  67. package/lib/defer.test.js +37 -0
  68. package/lib/escape_html.js +2 -0
  69. package/lib/extensions/_file_importer.js +2 -0
  70. package/lib/extensions/multi-tenant/database/row.js +27 -0
  71. package/lib/extensions/multi-tenant/database/table.js +30 -0
  72. package/lib/extensions/multi-tenant/database.js +8 -0
  73. package/lib/extensions/multi-tenant/index.js +4 -0
  74. package/lib/extensions/multi-tenant/migrations/1627976174_create_tenant_table_and_add_tenant_id_to_existing_tables.js +20 -0
  75. package/lib/extensions/multi-tenant/migrations/_file_importer.js +2 -0
  76. package/lib/extensions/multi-tenant/services/_file_importer.js +2 -0
  77. package/lib/extensions/multi-tenant/services/database.js +32 -0
  78. package/lib/html.js +72 -0
  79. package/lib/import_all.js +94 -0
  80. package/lib/index.js +11 -2
  81. package/lib/inflector.js +173 -0
  82. package/lib/lru_cache.js +53 -0
  83. package/lib/lru_cache.test.js +45 -0
  84. package/lib/markdown.js +58 -0
  85. package/lib/model.js +110 -0
  86. package/lib/project.js +72 -0
  87. package/lib/registry.js +130 -0
  88. package/lib/service_consumer.js +16 -0
  89. package/lib/service_factory.js +20 -0
  90. package/lib/services/_file_importer.js +1 -0
  91. package/lib/services/app.js +11 -0
  92. package/lib/services/args.js +9 -0
  93. package/lib/services/bot.js +69 -0
  94. package/lib/services/cli_utils.js +77 -0
  95. package/lib/services/client_builder.js +70 -0
  96. package/lib/services/config.js +66 -0
  97. package/lib/services/cookies.js +19 -0
  98. package/lib/services/create_model.js +8 -0
  99. package/lib/services/database.js +14 -0
  100. package/lib/services/defer.js +8 -0
  101. package/lib/services/fetch.js +115 -0
  102. package/lib/services/format_date.js +8 -0
  103. package/lib/services/fs_builder.js +132 -0
  104. package/lib/services/inflector.js +8 -0
  105. package/lib/services/initial_params.js +13 -0
  106. package/lib/services/params.js +13 -0
  107. package/lib/services/parse_html.js +8 -0
  108. package/lib/services/project.js +8 -0
  109. package/lib/services/render_form.js +165 -0
  110. package/lib/services/render_html.js +8 -0
  111. package/lib/services/render_markdown.js +9 -0
  112. package/lib/services/render_view.js +6 -0
  113. package/lib/services/repl.js +54 -0
  114. package/lib/services/run_command.js +8 -0
  115. package/lib/services/run_in_new_workspace.js +11 -0
  116. package/lib/services/send_mail.js +47 -0
  117. package/lib/services/server.js +105 -0
  118. package/lib/services/view.js +6 -0
  119. package/lib/singleton.js +13 -0
  120. package/lib/string_reader.js +22 -0
  121. package/lib/trapify.js +32 -0
  122. package/lib/unescape_html.js +2 -0
  123. package/lib/unescape_html.test.js +9 -0
  124. package/lib/util.js +3 -0
  125. package/lib/validation_error.js +7 -0
  126. package/lib/view.js +82 -0
  127. package/lib/view_file_importers/md.js +42 -0
  128. package/lib/views/_file_importer.js +1 -0
  129. package/lib/views/main/assets/javascripts/all.js.js +7 -0
  130. package/lib/views/main/assets/javascripts/all.js.map.js +7 -0
  131. package/lib/views/main/assets/stylesheets/all.css.js +28 -0
  132. package/lib/views/main/assets/stylesheets/components/button.css +43 -0
  133. package/lib/views/main/assets/stylesheets/components/card.css +29 -0
  134. package/lib/views/main/assets/stylesheets/components/form.css +4 -0
  135. package/lib/views/main/assets/stylesheets/components/frame.css +3 -0
  136. package/lib/views/main/assets/stylesheets/components/input.css +40 -0
  137. package/lib/views/main/assets/stylesheets/components/label.css +9 -0
  138. package/lib/views/main/assets/stylesheets/components/overlay.css +11 -0
  139. package/lib/views/main/assets/stylesheets/components/pagination.css +60 -0
  140. package/lib/views/main/assets/stylesheets/components/progress_bar.css +20 -0
  141. package/lib/views/main/assets/stylesheets/components/textarea.css +10 -0
  142. package/lib/views/main/assets/stylesheets/global.css +120 -0
  143. package/lib/views/main/assets/stylesheets/reset.css +74 -0
  144. package/lib/views/main/assets/stylesheets/vars.css +25 -0
  145. package/lib/virtual_node.js +171 -0
  146. package/lib/virtual_node.test.js +28 -0
  147. package/lib/workspace.js +21 -0
  148. package/package.json +28 -6
  149. package/lib/components/anchor.js +0 -22
  150. package/lib/components/frame.js +0 -49
  151. package/lib/components/index.js +0 -9
  152. package/lib/event_wrapper.js +0 -26
@@ -0,0 +1,74 @@
1
+
2
+ import { default as mimeTypes } from 'mime-types';
3
+
4
+ export default {
5
+ async run(){
6
+ this.pages = {};
7
+ const urls = this.viewNames.filter(path => !path.match(/(^|\/)_/)).map(path => {
8
+ return new URL(path, 'http://127.0.0.1/');
9
+ });
10
+
11
+ while(urls.length){
12
+ await this.crawlPage({ _url: urls.shift() });
13
+ }
14
+
15
+ const pages = Object.values(this.pages).filter(page => page.status == 200 && Object.keys(page.params).length == 1);
16
+ const { inProjectRootDir, generateDir, generateFile, echo } = this.fsBuilder;
17
+
18
+ await inProjectRootDir(async () => {
19
+ await generateDir('build/static', async () => {
20
+ while(pages.length){
21
+ const { params, headers } = pages.shift();
22
+ const contentType = headers['content-type'];
23
+
24
+ const path = params._url.pathname;
25
+ let filePath = path.replace(/^\//, '');
26
+ if(filePath.match(/(^|\/)$/)){
27
+ filePath = `${filePath}index`;
28
+ }
29
+ if(!filePath.match(/[^/]+\.[^/]+$/)){
30
+ filePath = `${filePath}.${mimeTypes.extension(contentType)}`
31
+ }
32
+
33
+ const data = (await this.fetch({ _url: new URL(path, 'http://127.0.0.1/') }))[2];
34
+
35
+ await generateFile(filePath, () => {
36
+ echo(data.join(''));
37
+ });
38
+ }
39
+ });
40
+ });
41
+ },
42
+
43
+ async crawlPage(params){
44
+ const hash = JSON.stringify(params);
45
+ if(this.pages[hash]) return;
46
+ const page = { params };
47
+ this.pages[hash] = page;
48
+ const [ status, headers, data ] = await this.fetch(params);
49
+ page.status = status;
50
+ page.headers = headers;
51
+ if(status != 200 || headers['content-type'] != 'text/html') return;
52
+ const html = data.join('');
53
+ const virtualDom = this.parseHtml(html);
54
+ const urls = this.extractUrls(virtualDom);
55
+ while(urls.length){
56
+ const url = urls.shift();
57
+ await this.crawlPage({ ...url.params, _url: url });
58
+ }
59
+ },
60
+
61
+ extractUrls(virtualDom){
62
+ const out = [];
63
+ virtualDom.traverse(({ attributes }) => {
64
+ ['src', 'href'].forEach(name => {
65
+ const value = attributes[name];
66
+ if(!value) return;
67
+ const url = new URL(value, 'http://127.0.0.1/');
68
+ if(url.host != '127.0.0.1') return;
69
+ out.push(url);
70
+ });
71
+ });
72
+ return out;
73
+ }
74
+ };
@@ -0,0 +1,44 @@
1
+
2
+ export default {
3
+ async run(){
4
+ const [ name = '' ] = this.args;
5
+ let normalizedName = name.replace(/^\//, '');
6
+ if(name == ''){
7
+ console.error('A view name must be given.');
8
+ process.exit();
9
+ }
10
+
11
+ if(!normalizedName.match(/\.[^\/]+$/)){
12
+ normalizedName = `${normalizedName}.js`;
13
+ }
14
+
15
+ const { inProjectRootDir, generateFile, line, indent } = this.fsBuilder;
16
+
17
+ await inProjectRootDir(async () => {
18
+
19
+ await generateFile(`lib/views/_file_importer.js`, { skipIfExists: true }, () => {
20
+ line();
21
+ line(`export { View as default } from 'pinstripe';`);
22
+ line();
23
+ });
24
+
25
+ await generateFile(`lib/views/${normalizedName}`, () => {
26
+ line();
27
+ line('export default {');
28
+ indent(() => {
29
+ line('render(){')
30
+ indent(() => {
31
+ line('return this.renderHtml`')
32
+ indent(() => {
33
+ line(`<h1>${normalizedName} view<h1></h1>`);
34
+ });
35
+ line('`;')
36
+ });
37
+ line('}')
38
+ });
39
+ line('};');
40
+ line();
41
+ });
42
+ });
43
+ }
44
+ };
@@ -0,0 +1,9 @@
1
+
2
+ import { Command } from 'pinstripe';
3
+
4
+ export default {
5
+ async run(){
6
+ await this.runCommand('migrate-database');
7
+ await this.runCommand('seed-database');
8
+ }
9
+ }
@@ -0,0 +1,15 @@
1
+
2
+ import chalk from 'chalk';
3
+ import { App } from 'pinstripe';
4
+
5
+ export default {
6
+ run(){
7
+ console.log('');
8
+ console.log('The following apps are available:');
9
+ console.log('');
10
+ App.names.forEach(appName => {
11
+ console.log(` * ${chalk.green(appName)} (composed of ${JSON.stringify(App.create(appName, this.context).compose())} views)`);
12
+ });
13
+ console.log('');
14
+ }
15
+ };
@@ -0,0 +1,15 @@
1
+
2
+ import chalk from 'chalk';
3
+ import { Command } from 'pinstripe';
4
+
5
+ export default {
6
+ run(){
7
+ console.log('');
8
+ console.log('The following commands are available:');
9
+ console.log('');
10
+ Command.names.forEach(commandName => {
11
+ console.log(` * ${chalk.green(commandName)}`);
12
+ });
13
+ console.log('');
14
+ }
15
+ };
@@ -0,0 +1,16 @@
1
+
2
+ import chalk from 'chalk';
3
+ import { Component } from 'pinstripe';
4
+
5
+ export default {
6
+ run(){
7
+ console.log('');
8
+ console.log('The following components are available:');
9
+ console.log('');
10
+ Component.names.forEach(componentName => {
11
+ console.log(` * ${chalk.green(componentName)}`);
12
+ });
13
+ console.log('');
14
+ }
15
+ };
16
+
@@ -0,0 +1,15 @@
1
+
2
+ import chalk from 'chalk';
3
+ import { Migration } from 'pinstripe/database';
4
+
5
+ export default {
6
+ run(){
7
+ console.log('');
8
+ console.log('The following migrations are available:');
9
+ console.log('');
10
+ Migration.names.forEach(migrationName => {
11
+ console.log(` * ${chalk.green(migrationName)}`);
12
+ });
13
+ console.log('');
14
+ }
15
+ };
@@ -0,0 +1,15 @@
1
+
2
+ import chalk from 'chalk';
3
+ import { Row } from 'pinstripe/database';
4
+
5
+ export default {
6
+ run(){
7
+ console.log('');
8
+ console.log('The following models are available:');
9
+ console.log('');
10
+ Row.names.forEach(modelName => {
11
+ console.log(` * ${chalk.green(modelName)}`);
12
+ });
13
+ console.log('');
14
+ }
15
+ };
@@ -0,0 +1,15 @@
1
+
2
+ import chalk from 'chalk';
3
+ import { ServiceFactory } from 'pinstripe';
4
+
5
+ export default {
6
+ run(){
7
+ console.log('');
8
+ console.log('The following views are available:');
9
+ console.log('');
10
+ ServiceFactory.names.forEach(serviceFactoryName => {
11
+ console.log(` * ${chalk.green(serviceFactoryName)}`);
12
+ });
13
+ console.log('');
14
+ }
15
+ };
@@ -0,0 +1,39 @@
1
+
2
+ import chalk from 'chalk';
3
+ import { App, View } from 'pinstripe';
4
+
5
+ export default {
6
+ run(){
7
+ const { extractOptions } = this.cliUtils;
8
+
9
+ const { app } = extractOptions();
10
+
11
+ if(app){
12
+ this.listComposedViews(typeof app == 'string' ? app : 'main');
13
+ } else {
14
+ this.listAllViews();
15
+ }
16
+ },
17
+
18
+ listComposedViews(appName){
19
+ const { viewNames, resolveView } = View.mapperFor(App.create(appName, this.context).compose());
20
+ console.log('');
21
+ console.log(`The following views have been composed for app "${appName}":`);
22
+ console.log('');
23
+ viewNames.forEach(viewName => {
24
+ console.log(` * ${chalk.green(viewName)} -> ${chalk.green(resolveView(viewName))}`);
25
+ });
26
+ console.log('');
27
+ },
28
+
29
+ listAllViews(){
30
+ console.log('');
31
+ console.log(`The following views are available:`);
32
+ console.log('');
33
+ View.names.forEach(viewName => {
34
+ console.log(` * ${chalk.green(viewName)}`);
35
+ });
36
+ console.log('');
37
+ }
38
+ };
39
+
@@ -0,0 +1,6 @@
1
+
2
+ export default {
3
+ async run(){
4
+ await this.database.migrate();
5
+ }
6
+ };
@@ -0,0 +1,12 @@
1
+
2
+ export default {
3
+ meta(){
4
+ this.schedule('*/5 * * * *');
5
+ },
6
+
7
+ minutesUntilExpiry: 30,
8
+
9
+ async run(){
10
+ // await this.database.withoutMultiTenancy.sessions.lastAccessedAtLt(Date.now() - (1000 * 60 * this.minutesUntilExpiry)).delete();
11
+ }
12
+ };
@@ -0,0 +1,9 @@
1
+
2
+ import { Command } from 'pinstripe';
3
+
4
+ export default {
5
+ async run(){
6
+ await this.runCommand('drop-database');
7
+ await this.runCommand('init-database');
8
+ }
9
+ };
@@ -0,0 +1,6 @@
1
+
2
+ export default {
3
+ run(){
4
+ // do nothing
5
+ }
6
+ };
@@ -0,0 +1,6 @@
1
+
2
+ export default {
3
+ async run(){
4
+ console.log(JSON.stringify(await this.config, null, 2));
5
+ }
6
+ };
@@ -0,0 +1,6 @@
1
+
2
+ export default {
3
+ async run(){
4
+ await this.repl.start()
5
+ }
6
+ };
@@ -0,0 +1,31 @@
1
+
2
+ export default {
3
+ run(){
4
+ const { extractOptions } = this.cliUtils;
5
+
6
+ const { app, withoutBot } = extractOptions({
7
+ app: `main:${process.env.HOST || '127.0.0.1'}:${parseInt(process.env.PORT || '3000')}`,
8
+ withoutBot: false
9
+ });
10
+
11
+
12
+ const apps = [];
13
+ let currentPort = 3000;
14
+
15
+ app.trim().split(/\s+/).forEach((app) => {
16
+ const [name, ...serverConfig] = app.split(/:/);
17
+ const [ port, host = '127.0.0.1'] = serverConfig.reverse();
18
+
19
+ if(port){
20
+ apps.push({ name, port: parseInt(port), host });
21
+ } else {
22
+ while(apps.filter(app => app.host == host).map(({ port }) => port).includes(currentPort)) currentPort++;
23
+ apps.push({ name, port: currentPort, host });
24
+ }
25
+ });
26
+
27
+ this.server.start(apps);
28
+
29
+ // if(!withoutBot) this.bot.start();
30
+ }
31
+ };
package/lib/component.js CHANGED
@@ -1,7 +1,13 @@
1
1
 
2
- import { Class, TEXT_ONLY_TAGS, Inflector, VirtualNode, Registry } from "haberdash";
2
+ import { fileURLToPath } from 'url'; // pinstripe-if-client: const fileURLToPath = undefined;
3
3
 
4
- import { EventWrapper } from './event_wrapper.js';
4
+ import { Class } from './class.js';
5
+ import { TEXT_ONLY_TAGS } from './constants.js';
6
+ import { Inflector } from './inflector.js';
7
+ import { VirtualNode } from './virtual_node.js';
8
+ import { Registry } from './registry.js';
9
+ import { ComponentEvent } from './component_event.js';
10
+ import { Client } from './client.js'; // pinstripe-if-client: const Client = undefined;
5
11
 
6
12
  export const Component = Class.extend().include({
7
13
  meta(){
@@ -24,6 +30,30 @@ export const Component = Class.extend().include({
24
30
  return Inflector.instance.dasherize(name);
25
31
  }
26
32
  });
33
+
34
+ this.FileImporter.register('js', {
35
+ meta(){
36
+ const { importFile } = this.prototype;
37
+
38
+ this.include({
39
+ async importFile(params){
40
+ const { filePath, relativeFilePathWithoutExtension } = params;
41
+ if((await import(filePath)).default){
42
+ Client.instance.addModule(`
43
+ import { Component } from ${JSON.stringify(fileURLToPath(`${import.meta.url}/../index.js`))};
44
+ import include from ${JSON.stringify(filePath)};
45
+ Component.register(${JSON.stringify(relativeFilePathWithoutExtension)}, include);
46
+ `);
47
+ } else {
48
+ Client.instance.addModule(`
49
+ import ${JSON.stringify(filePath)};
50
+ `);
51
+ }
52
+ return importFile.call(this, params);
53
+ }
54
+ })
55
+ }
56
+ })
27
57
  },
28
58
 
29
59
  initialize(node, skipInit = false){
@@ -46,8 +76,9 @@ export const Component = Class.extend().include({
46
76
  this.setTimeout(() => this.node.focus());
47
77
  }
48
78
 
49
- const { autosubmit, trigger } = this.data;
79
+ const { autosubmit, trigger, decorate } = this.data;
50
80
 
81
+ // replace with pinstripe-autosubmitter?
51
82
  if(autosubmit){
52
83
  let hash = JSON.stringify(this.values);
53
84
  this.setInterval(() => {
@@ -59,6 +90,7 @@ export const Component = Class.extend().include({
59
90
  }, 100);
60
91
  }
61
92
 
93
+ // replace with script?
62
94
  if(trigger){
63
95
  this.setTimeout(() => {
64
96
  this.trigger(trigger);
@@ -103,7 +135,9 @@ export const Component = Class.extend().include({
103
135
  },
104
136
 
105
137
  get realParent(){
106
- return this.node.parentNode ? this.constructor.instanceFor(this.node.parentNode) : null;
138
+ if(this.node.parentNode) return this.constructor.instanceFor(this.node.parentNode);
139
+ if(this.node.host instanceof Element) return this.constructor.instanceFor(this.node.host);
140
+ return null;
107
141
  },
108
142
 
109
143
  get parent(){
@@ -122,6 +156,10 @@ export const Component = Class.extend().include({
122
156
  return out;
123
157
  },
124
158
 
159
+ get parentsIncludingThis(){
160
+ return [this, ...this.parents];
161
+ },
162
+
125
163
  get children(){
126
164
  return [...this.node.childNodes].map(
127
165
  node => this.constructor.instanceFor(node)
@@ -241,7 +279,7 @@ export const Component = Class.extend().include({
241
279
  },
242
280
 
243
281
  get document(){
244
- return this.parents.find(({ isDocument }) => isDocument) || this;
282
+ return this.find('parentsIncludingThis', ({ isDocument }) => isDocument);
245
283
  },
246
284
 
247
285
  get overlay(){
@@ -251,6 +289,7 @@ export const Component = Class.extend().include({
251
289
  get shadow(){
252
290
  if(!this.node.shadowRoot){
253
291
  this.node.attachShadow({ mode: 'open' });
292
+ this.shadow.observe({ add: true }, component => component.descendants);
254
293
  this.shadow.patch(`<slot>`);
255
294
  }
256
295
  return Component.instanceFor(this.node.shadowRoot);
@@ -277,7 +316,7 @@ export const Component = Class.extend().include({
277
316
  const selector = args.pop()
278
317
 
279
318
  const wrapperFn = (event, ...args) => {
280
- const eventWrapper = EventWrapper.instanceFor(event)
319
+ const eventWrapper = ComponentEvent.instanceFor(event)
281
320
  if(selector){
282
321
  if(eventWrapper.target.is(selector)){
283
322
  return fn.call(eventWrapper.target, eventWrapper, ...args);
@@ -325,8 +364,8 @@ export const Component = Class.extend().include({
325
364
 
326
365
  remove(){
327
366
  if(this.realParent){
328
- clearTimers.call(this);
329
- if(this.realParent) this.realParent.node.removeChild(this.node);
367
+ clean.call(this);
368
+ this.realParent.node.removeChild(this.node);
330
369
  }
331
370
  return this;
332
371
  },
@@ -414,20 +453,25 @@ export const Component = Class.extend().include({
414
453
  },
415
454
 
416
455
  async fetch(url, options = {}){
456
+ const { minimumDelay = 0, ...otherOptions } = options;
417
457
  const { progressBar } = this.document;
418
458
  const frame = this.frame || this;
419
459
  const normalizedUrl = new URL(url, frame.url);
420
460
  const abortController = new AbortController();
421
461
  this._registeredAbortControllers.push(abortController);
422
462
  progressBar.start();
463
+ let minimumDelayTimeout;
423
464
  const cleanUp = () => {
465
+ clearTimeout(minimumDelayTimeout);
424
466
  this._registeredAbortControllers = this._registeredAbortControllers.filter(item => item !== abortController);
425
467
  progressBar.stop();
426
468
  };
427
469
  try {
428
- const out = await fetch(normalizedUrl, Object.assign({
429
- signal: abortController.signal
430
- }, options));
470
+ const promises = [
471
+ fetch(normalizedUrl, { signal: abortController.signal, ...otherOptions }),
472
+ new Promise(resolve => minimumDelayTimeout = setTimeout(resolve, minimumDelay))
473
+ ];
474
+ const [ out ] = await Promise.all(promises);
431
475
  cleanUp();
432
476
  return out;
433
477
  } catch(e){
@@ -454,7 +498,6 @@ export const Component = Class.extend().include({
454
498
  const [ collection, selector ] = args;
455
499
  return this[collection].filter(item => item.is(selector));
456
500
  }
457
-
458
501
  });
459
502
 
460
503
  const matchesSelector = (() => {
@@ -464,10 +507,15 @@ const matchesSelector = (() => {
464
507
  })();
465
508
 
466
509
  function cleanChildren(){
510
+ if(this.node.shadowRoot){
511
+ this.shadow.children.forEach(child => clean.call(child));
512
+ }
467
513
  this.children.forEach(child => clean.call(child));
468
514
  }
469
515
 
470
516
  function clean(){
517
+ this.trigger('clean', { bubbles: false });
518
+
471
519
  [...this.node.childNodes].forEach(node => node._component && clean.call(node._component));
472
520
 
473
521
  while(this._registeredEventListeners.length){
@@ -494,6 +542,9 @@ function clearTimers(){
494
542
  }
495
543
 
496
544
  function initChildren(){
545
+ if(this.node.shadowRoot){
546
+ this.shadow.children.forEach(child => initChildren.call(child));
547
+ }
497
548
  this.children.forEach(child => initChildren.call(child));
498
549
  }
499
550
 
@@ -516,13 +567,19 @@ function createVirtualNode(html){
516
567
  }
517
568
 
518
569
  function patch(attributes, virtualChildren){
519
- const isEmptyFrame = this.is('.frame') && virtualChildren.length == 0;
570
+ const isFrame = this.type == 'pinstripe-frame' || this.attributes['data-component'] == 'pinstripe-frame';
571
+ const isEmptyFrame = isFrame && virtualChildren.length == 0;
520
572
  if(isEmptyFrame && attributes['data-load-on-init'] === undefined){
521
573
  attributes['data-load-on-init'] = 'true';
522
574
  }
523
575
  patchAttributes.call(this, attributes);
524
576
  if(isEmptyFrame) return;
525
- patchChildren.call(this, virtualChildren);
577
+ if(this.is('pinstripe-silo, [data-component="pinstripe-silo"]')){
578
+ patchChildren.call(this.shadow, virtualChildren);
579
+ patchChildren.call(this, []);
580
+ } else {
581
+ patchChildren.call(this, virtualChildren);
582
+ }
526
583
  }
527
584
 
528
585
  function patchAttributes(attributes){
@@ -534,11 +591,12 @@ function patchAttributes(attributes){
534
591
  const currentAttributes = this.attributes;
535
592
  Object.keys(currentAttributes).forEach((key) => {
536
593
  if(attributes[key] === undefined){
537
- this.node.removeAttribute(key);
594
+ Element.prototype.removeAttribute.call(this.node, key); // work around for https://github.com/cypress-io/cypress/issues/26206
595
+ // this.node.removeAttribute(key);
538
596
  }
539
597
  })
540
598
  Object.keys(attributes).forEach((key) => {
541
- if(currentAttributes[key] != attributes[key]){
599
+ if(!currentAttributes.hasOwnProperty(key) || currentAttributes[key] != attributes[key]){
542
600
  this.node.setAttribute(key, attributes[key]);
543
601
  if(key == 'value'){
544
602
  this.node.value = attributes[key];
@@ -601,10 +659,17 @@ function insert(virtualNode, referenceChild, returnComponent = true){
601
659
  insert.call(new Component(node, true), child, null, false);
602
660
  })
603
661
 
604
- this.node.insertBefore(
605
- node,
606
- referenceChild && referenceChild.node
607
- );
662
+ if(this.is('pinstripe-silo, [data-component="pinstripe-silo"]')){
663
+ this.shadow.node.insertBefore(
664
+ node,
665
+ referenceChild && referenceChild.node
666
+ );
667
+ } else {
668
+ this.node.insertBefore(
669
+ node,
670
+ referenceChild && referenceChild.node
671
+ );
672
+ }
608
673
 
609
674
  if(returnComponent){
610
675
  return Component.instanceFor(node);
@@ -632,17 +697,4 @@ function normalizeVirtualNode(){
632
697
  }
633
698
  }
634
699
 
635
- EventWrapper.Component = Component;
636
-
637
- [
638
- ['#document', 'pinstripe-document'],
639
- ['a', 'pinstripe-anchor'],
640
- ['body', 'pinstripe-body'],
641
- ['form', 'pinstripe-form']
642
- ].forEach(([name, include]) => {
643
- Component.register(name, {
644
- meta(){
645
- this.include(include);
646
- }
647
- })
648
- });
700
+ ComponentEvent.Component = Component;
@@ -0,0 +1,28 @@
1
+
2
+ import { Class } from './class.js';
3
+ import { trapify } from './trapify.js';
4
+
5
+ export const ComponentEvent = Class.extend().include({
6
+ meta(){
7
+ this.assignProps({
8
+ instanceFor(event){
9
+ if(!event._componentEvent){
10
+ event._componentEvent = ComponentEvent.new(event);
11
+ }
12
+ return event._componentEvent;
13
+ }
14
+ });
15
+ },
16
+
17
+ initialize(event){
18
+ this.event = event;
19
+ return trapify(this);
20
+ },
21
+
22
+ __get(target, name){
23
+ const out = target.event[name];
24
+ if(out instanceof Node) return ComponentEvent.Component.instanceFor(out);
25
+ if(typeof out == 'function') return (...args) => out.call(target.event, ...args);
26
+ return out;
27
+ }
28
+ });
@@ -0,0 +1 @@
1
+ export { Component as default } from 'pinstripe';
@@ -0,0 +1,27 @@
1
+
2
+ import { loadFrame, getFrame } from "./helpers.js";
3
+
4
+ export default {
5
+ initialize(...args){
6
+ this.constructor.parent.prototype.initialize.call(this, ...args);
7
+
8
+ const { ignoreEventsFromChildren = false } = this.data;
9
+ this.on('click', (event) => {
10
+ if(ignoreEventsFromChildren && event.target != this) return;
11
+ const { confirm, target = '_self', method = 'GET', href, placeholder } = { ...this.attributes, ...this.data };
12
+ if(new URL(href, window.location.href).host != window.location.host) return;
13
+ event.preventDefault();
14
+ event.stopPropagation();
15
+ loadFrame.call(this, confirm, target, method, href, placeholder);
16
+ });
17
+
18
+ const { target = '_self', method = 'GET', href, preload, placeholder } = { ...this.attributes, ...this.data };
19
+ if(method == 'GET' && target != '_blank'){
20
+ const frame = target == '_overlay' ? this.frame : getFrame.call(this, target);
21
+ if(preload != undefined) this.document.preload(new URL(href, frame.url));
22
+ if(placeholder != undefined) this.document.preload(new URL(placeholder, frame.url));
23
+ }
24
+
25
+ if(this.is('input, textarea')) this.on('keyup', (event) => this.trigger('click'));
26
+ }
27
+ };