@pb33f/cowboy-components 0.3.2 → 0.3.4

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 (31) hide show
  1. package/dist/components/manage-ruleset/manage-ruleset.css.js +14 -3
  2. package/dist/components/manage-ruleset/manage-ruleset.d.ts +3 -0
  3. package/dist/components/manage-ruleset/manage-ruleset.js +85 -2
  4. package/dist/components/manage-ruleset/rule-input.js +8 -1
  5. package/dist/components/manage-ruleset/rule.css.js +3 -1
  6. package/dist/components/manage-ruleset/rule.js +42 -3
  7. package/dist/components/model-renderer/schema.js +10 -0
  8. package/dist/components/paginator/paginator-navigator.js +3 -0
  9. package/dist/components/paginator/paginator.css.js +5 -2
  10. package/dist/components/paginator/paginator.d.ts +1 -0
  11. package/dist/components/paginator/paginator.js +9 -3
  12. package/dist/components/problems-overview/diagnostic-evaluation.js +0 -3
  13. package/dist/components/problems-overview/problem-overview-group.d.ts +2 -0
  14. package/dist/components/problems-overview/problem-overview-group.js +15 -2
  15. package/dist/components/problems-overview/problems-overview.js +8 -2
  16. package/dist/components/the-doctor/sparks.d.ts +17 -0
  17. package/dist/components/the-doctor/sparks.js +81 -0
  18. package/dist/components/the-doctor/the-doctor.css.js +74 -26
  19. package/dist/components/the-doctor/the-doctor.d.ts +31 -1
  20. package/dist/components/the-doctor/the-doctor.js +234 -32
  21. package/dist/cowboy-components.umd.cjs +1793 -1642
  22. package/dist/events/doctor.d.ts +6 -2
  23. package/dist/events/doctor.js +1 -0
  24. package/dist/model/channels.d.ts +11 -0
  25. package/dist/model/channels.js +11 -0
  26. package/dist/model/errors.d.ts +1 -1
  27. package/dist/services/header-service.d.ts +5 -0
  28. package/dist/services/header-service.js +16 -0
  29. package/dist/services/linting-service.d.ts +1 -1
  30. package/dist/services/linting-service.js +19 -9
  31. package/package.json +1 -1
@@ -27,10 +27,21 @@ export default css `
27
27
  color: var(--primary-color);
28
28
  margin-top: 22px;
29
29
  }
30
+
31
+ sl-icon-button {
32
+ font-size: 1.2rem;
33
+ color: var(--primary-color);
34
+ margin-top: 22px;
35
+ }
36
+
37
+
38
+ sl-icon-button.sort {
39
+ margin: 0;
40
+ padding: 0;
41
+ }
30
42
 
31
- sl-icon-button#save-button {
32
- color: var(--warn-color);
33
- animation: pulse-animation 1.5s infinite;
43
+ sl-icon-button.sort::part(base) {
44
+ padding: 7px 5px 2px 10px
34
45
  }
35
46
 
36
47
  @keyframes pulse-animation {
@@ -19,6 +19,8 @@ export declare class ManageRuleset extends LitElement {
19
19
  customWipeDialog: SlDialog;
20
20
  confirmWipeButton: SlButton;
21
21
  allRulesSwitch: SlSwitch;
22
+ sortAlpha: boolean;
23
+ sortSeverity: boolean;
22
24
  private _defaultRuleset;
23
25
  private _owaspRuleset;
24
26
  private _allRuleset;
@@ -43,6 +45,7 @@ export declare class ManageRuleset extends LitElement {
43
45
  clearRuleProblems(): void;
44
46
  processBadRules(ruleError: RuleError[]): void;
45
47
  rulesetSaved(ruleset: RuleSet, returnedRuleset: RuleSet): void;
48
+ private _noSort;
46
49
  private dirty;
47
50
  private copyActiveRulesetCustom;
48
51
  private buildConfig;
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import '@shoelace-style/shoelace/dist/components/radio-group/radio-group.js';
8
8
  import '@shoelace-style/shoelace/dist/components/radio-button/radio-button.js';
9
9
  import '@shoelace-style/shoelace/dist/components/dialog/dialog.js';
10
- import { customElement, query } from "lit/decorators.js";
10
+ import { customElement, property, query } from "lit/decorators.js";
11
11
  import { html, LitElement } from "lit";
12
12
  import manageRulesetCss from "./manage-ruleset.css.js";
13
13
  import { RuleComponent } from "./rule.js";
@@ -26,6 +26,7 @@ export const customRuleset = "custom";
26
26
  let ManageRuleset = class ManageRuleset extends LitElement {
27
27
  constructor() {
28
28
  super();
29
+ this._noSort = false;
29
30
  this._defaultRules = [];
30
31
  this._owaspRules = [];
31
32
  this._allRules = [];
@@ -33,6 +34,8 @@ let ManageRuleset = class ManageRuleset extends LitElement {
33
34
  this._rulesetConfig = { ruleMapping: new Map(), allRulesSwitch: true };
34
35
  this.currentRuleset = defaultRuleset;
35
36
  this.allRulesEnabled = true;
37
+ this.sortAlpha = true;
38
+ this.sortSeverity = false;
36
39
  // @ts-ignore
37
40
  this.addEventListener(RulesetDirty, this.dirty.bind(this));
38
41
  this.addEventListener(RulesetSaved, this.rulesetUpdated.bind(this));
@@ -165,6 +168,7 @@ let ManageRuleset = class ManageRuleset extends LitElement {
165
168
  else {
166
169
  this.copyActiveRulesetCustom();
167
170
  }
171
+ this._noSort = true;
168
172
  }
169
173
  copyActiveRulesetCustom(submittedRule) {
170
174
  const customRules = [];
@@ -493,10 +497,67 @@ let ManageRuleset = class ManageRuleset extends LitElement {
493
497
  }
494
498
  render() {
495
499
  let selectAll = html ``;
500
+ let sortBySeverity = html ``;
501
+ let sortByAlpha = html ``;
496
502
  let numRules = 0;
497
503
  if (this._activeRuleset) {
498
504
  numRules = this._activeRuleset.length;
499
505
  }
506
+ const priority = { error: 0, warn: 1, info: 2 };
507
+ // if sortSeverity or sortAlpha is true, sort the ruleset by alpha or severity, or both starting
508
+ // with severity and then alpha
509
+ if (this.sortSeverity && !this._noSort) {
510
+ this._activeRuleset?.sort((a, b) => {
511
+ if (a && b) {
512
+ if (a.rule && b.rule) {
513
+ if (a.rule.severity === b.rule.severity) {
514
+ if (a.rule.id && b.rule.id) {
515
+ if (this.sortAlpha) {
516
+ return a.rule.id.localeCompare(b.rule.id);
517
+ }
518
+ else {
519
+ return b.rule.id.localeCompare(a.rule.id);
520
+ }
521
+ }
522
+ }
523
+ if (a.rule.severity && b.rule.severity) {
524
+ return priority[b.rule.severity] - priority[a.rule.severity];
525
+ }
526
+ }
527
+ }
528
+ return 0;
529
+ });
530
+ }
531
+ else {
532
+ if (!this._noSort) {
533
+ this._activeRuleset?.sort((a, b) => {
534
+ if (a && b) {
535
+ if (a.rule && b.rule) {
536
+ if (a.rule.severity === b.rule.severity) {
537
+ if (a.rule.id && b.rule.id) {
538
+ if (this.sortAlpha) {
539
+ return a.rule.id.localeCompare(b.rule.id);
540
+ }
541
+ else {
542
+ return b.rule.id.localeCompare(a.rule.id);
543
+ }
544
+ }
545
+ }
546
+ if (a.rule.severity && b.rule.severity) {
547
+ if (this.sortSeverity) {
548
+ return priority[b.rule.severity] - priority[a.rule.severity];
549
+ }
550
+ else {
551
+ return priority[a.rule.severity] - priority[b.rule.severity];
552
+ }
553
+ }
554
+ }
555
+ }
556
+ return 0;
557
+ });
558
+ }
559
+ }
560
+ this._noSort = false;
500
561
  if (numRules > 0) {
501
562
  selectAll = html `
502
563
  <div class="toggle-allcheck">
@@ -506,6 +567,18 @@ let ManageRuleset = class ManageRuleset extends LitElement {
506
567
  </sl-switch>
507
568
  </div>
508
569
  `;
570
+ sortByAlpha = html `<div class="sort-by-alpha">
571
+ <sl-tooltip content="Sort alphabetically" placement="top">
572
+ <sl-icon-button @click="${() => { this.sortAlpha = !this.sortAlpha; }}"
573
+ name="${this.sortAlpha ? 'sort-alpha-down' : 'sort-alpha-down-alt'}" class="sort"></sl-icon-button>
574
+ </sl-tooltip>
575
+ </div>`;
576
+ sortBySeverity = html `<div class="sort-by-severity">
577
+ <sl-tooltip content="Sort by severity" placement="top">
578
+ <sl-icon-button @click="${() => { this.sortSeverity = !this.sortSeverity; }}"
579
+ name="${this.sortSeverity ? 'sort-down-alt' : 'sort-down'}" class="sort"></sl-icon-button>
580
+ </sl-tooltip>
581
+ </div>`;
509
582
  }
510
583
  let rules = html `
511
584
  <div class="pb33f-loader">
@@ -552,7 +625,11 @@ let ManageRuleset = class ManageRuleset extends LitElement {
552
625
  </div>
553
626
  </div>
554
627
  <div class="ruleset-body">
555
- ${selectAll}
628
+ <div style="display: flex;">
629
+ ${selectAll}
630
+ ${sortByAlpha}
631
+ ${sortBySeverity}
632
+ </div>
556
633
  ${rules}
557
634
  </div>
558
635
  </div>
@@ -594,6 +671,12 @@ __decorate([
594
671
  __decorate([
595
672
  query('sl-switch')
596
673
  ], ManageRuleset.prototype, "allRulesSwitch", void 0);
674
+ __decorate([
675
+ property({ type: Boolean })
676
+ ], ManageRuleset.prototype, "sortAlpha", void 0);
677
+ __decorate([
678
+ property({ type: Boolean })
679
+ ], ManageRuleset.prototype, "sortSeverity", void 0);
597
680
  ManageRuleset = __decorate([
598
681
  customElement('pb33f-manage-ruleset')
599
682
  ], ManageRuleset);
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { customElement, property, query, state } from "lit/decorators.js";
8
8
  import { html, LitElement } from "lit";
9
9
  import { ProblemDrawerEventType } from "../problem-list/details-drawer.js";
10
- import { OpenProblemDrawer, RuleNameUpdated, RulesetDirty } from "../../events/doctor";
10
+ import { OpenProblemDrawer, RuleNameUpdated, RulesetDirty, SeverityChanged } from "../../events/doctor";
11
11
  import { RuleActionComponent } from "./rule-action.js";
12
12
  import ruleCss from "./rule.css.js";
13
13
  import formsCss from "../../css/forms.css.js";
@@ -112,6 +112,13 @@ let RuleInputComponent = class RuleInputComponent extends LitElement {
112
112
  }
113
113
  updateSeverity() {
114
114
  this.rule.severity = this.severity.value;
115
+ this.dispatchEvent(new CustomEvent(SeverityChanged, {
116
+ bubbles: true,
117
+ composed: true,
118
+ detail: {
119
+ severity: this.rule.severity
120
+ }
121
+ }));
115
122
  this.dirty();
116
123
  }
117
124
  updateCategory() {
@@ -62,7 +62,9 @@ export default css `
62
62
 
63
63
  sl-details::part(header) {
64
64
  font-size: 0.9rem;
65
- padding: 5px;
65
+ padding-top: 5px;
66
+ padding-bottom: 8px;
67
+ padding-left: 0;
66
68
  font-family: var(--font-stack-bold), monospace;
67
69
  }
68
70
 
@@ -15,10 +15,12 @@ import ruleCss from "./rule.css.js";
15
15
  import formsCss from "../../css/forms.css.js";
16
16
  import buttonCss from "../../css/button.css.js";
17
17
  import "./rule-action.js";
18
- import { RuleClicked, RuleNameUpdated, RulesetDirty } from "../../events/doctor.js";
18
+ import { RuleClicked, RuleNameUpdated, RulesetDirty, SeverityChanged } from "../../events/doctor.js";
19
19
  import { RuleInputComponent } from "./rule-input.js";
20
20
  import linksCss from "../../css/links.css.js";
21
21
  import listsCss from "../../css/lists.css.js";
22
+ import { NodeType } from "../../model/node_type.js";
23
+ import { IconColor, IconSize } from "../model-icon/model-icon.js";
22
24
  let RuleComponent = class RuleComponent extends LitElement {
23
25
  constructor(rule, id, custom) {
24
26
  super();
@@ -35,6 +37,11 @@ let RuleComponent = class RuleComponent extends LitElement {
35
37
  this.ruleInput.addEventListener(RuleNameUpdated, (evt) => {
36
38
  this.nameUpdated(evt.detail.name);
37
39
  });
40
+ //@ts-ignore
41
+ this.ruleInput.addEventListener(SeverityChanged, (evt) => {
42
+ this.rule.severity = evt.detail.severity;
43
+ this.requestUpdate();
44
+ });
38
45
  }
39
46
  nameUpdated(name) {
40
47
  this.rule.id = name;
@@ -108,6 +115,38 @@ let RuleComponent = class RuleComponent extends LitElement {
108
115
  </div>
109
116
  </div>`;
110
117
  }
118
+ let summary = html ``;
119
+ switch (this.rule.severity) {
120
+ case 'error':
121
+ summary = html `
122
+ <div slot="summary">
123
+ <pb33f-model-icon style="margin-right: 5px;"
124
+ icon="${NodeType.ERROR}"
125
+ color="${IconColor.error}"
126
+ size="${IconSize.small}"></pb33f-model-icon>
127
+ ${this.rule.id}
128
+ </div>`;
129
+ break;
130
+ case 'warn':
131
+ summary = html `<div slot="summary">
132
+ <pb33f-model-icon style="margin-right: 5px;"
133
+ icon="${NodeType.WARNING}"
134
+ color="${IconColor.warning}"
135
+ size="${IconSize.small}"></pb33f-model-icon>
136
+ ${this.rule.id}
137
+ </div>`;
138
+ break;
139
+ case 'info':
140
+ summary = html `
141
+ <div slot="summary">
142
+ <pb33f-model-icon style="margin-right: 5px;"
143
+ icon="${NodeType.INFO}"
144
+ color="${IconColor.primary}"
145
+ size="${IconSize.small}"></pb33f-model-icon>
146
+ ${this.rule.id}
147
+ </div>`;
148
+ break;
149
+ }
111
150
  return html `
112
151
  <div class="rule">
113
152
  <div class="check">
@@ -115,8 +154,8 @@ let RuleComponent = class RuleComponent extends LitElement {
115
154
  </div>
116
155
  ${errorCol}
117
156
  <div class="details">
118
- <sl-details summary="${this.rule.id}"
119
- class="${this.error ? 'error-rule' : ''}" @sl-show="${this.opened}">
157
+ <sl-details class="${this.error ? 'error-rule' : ''}" @sl-show="${this.opened}">
158
+ ${summary}
120
159
  ${errorBox}
121
160
  ${this.ruleInput}
122
161
  </sl-details>
@@ -61,6 +61,16 @@ let RenderedSchemaNodeComponent = class RenderedSchemaNodeComponent extends HasE
61
61
  if (typeof this.schema !== 'object') {
62
62
  return html `<div class="schema-item">${this.schema}</div>`;
63
63
  }
64
+ // check if this is just a string array, if so, just render it
65
+ if (Array.isArray(this.schema) && this.schema.every(item => typeof item === 'string')) {
66
+ return html `
67
+ <div class="schema-item" style="display: block">
68
+
69
+ ${this.schema.map((item, index) => {
70
+ return html `<div>[${index}] <code class="root" style="margin-left: 2px">${item}</code></div>`;
71
+ })}
72
+ </div>`;
73
+ }
64
74
  const sch = this.schema;
65
75
  if (isHasRef(sch)) {
66
76
  const segs = this.schema.$ref?.split('/');
@@ -90,6 +90,9 @@ let PaginatorNavigation = class PaginatorNavigation extends LitElement {
90
90
  }
91
91
  }
92
92
  render() {
93
+ if (this.totalItems == 0) {
94
+ return html ``;
95
+ }
93
96
  if (this.currentPage == 1) {
94
97
  this.togglePrev(true);
95
98
  }
@@ -21,18 +21,21 @@ export default css `
21
21
  }
22
22
 
23
23
  .no-values {
24
- width: 400px;
25
- margin: 50px auto;
24
+ width: 500px;
25
+ margin: 0 auto;
26
+ padding-top: 50px;
26
27
  text-align: center;
27
28
  font-size: 1.9em;
28
29
  color: var(--font-color-sub3);
29
30
  font-family: var(--font-stack-bold), monospace;
31
+ overflow-y: hidden;
30
32
 
31
33
  }
32
34
 
33
35
  .no-values sl-icon {
34
36
  margin-bottom: 30px;
35
37
  font-size: 5em;
38
+
36
39
  }
37
40
 
38
41
  `;
@@ -9,6 +9,7 @@ export declare class Paginator extends LitElement {
9
9
  label: string;
10
10
  activeIndex: number;
11
11
  private renderValues;
12
+ private sparks;
12
13
  private paginatorNavigator;
13
14
  constructor();
14
15
  nextPage(event: CustomEvent): void;
@@ -9,9 +9,11 @@ import { html, LitElement } from "lit";
9
9
  import { PaginatorNavigation } from "./paginator-navigator.js";
10
10
  import { PaginatorFirstPage, PaginatorLastPage, PaginatorNextPage, PaginatorPreviousPage } from "./paginator-events.js";
11
11
  import paginatorCss from "./paginator.css.js";
12
+ import { PixelSparks } from "../the-doctor/sparks";
12
13
  let Paginator = class Paginator extends LitElement {
13
14
  constructor() {
14
15
  super();
16
+ this.sparks = new PixelSparks();
15
17
  this.currentPage = 1;
16
18
  this.totalPages = 1;
17
19
  this.totalItems = 0;
@@ -80,11 +82,15 @@ let Paginator = class Paginator extends LitElement {
80
82
  this.renderValues = this.values?.slice(this.paginatorNavigator.getRangeStart(), this.paginatorNavigator.getRangeEnd());
81
83
  }
82
84
  render() {
85
+ let sparks = new PixelSparks();
83
86
  if (this.renderValues?.length === 0 || !this.renderValues) {
84
- return html `<div class="no-values">
85
- <sl-icon name="x-square"></sl-icon><br/>
87
+ return html `
88
+ <div class="no-values" style="position: relative">
89
+ <div style="position: absolute; width: 100%; top: -50px; left: 0;">${this.sparks}</div>
90
+ <sl-icon name="x-square"></sl-icon><br/>
86
91
  no results
87
- </div>`;
92
+ </div>
93
+ `;
88
94
  }
89
95
  return html `
90
96
  ${this.paginatorNavigator}
@@ -60,9 +60,6 @@ let DiagnosticEvaluation = class DiagnosticEvaluation extends LitElement {
60
60
  render() {
61
61
  this.links = [];
62
62
  let parsed = this.convertToLinks(marked.parse(this.diagnosis).toString());
63
- this.links.sort((a, b) => {
64
- return a.localeCompare(b);
65
- });
66
63
  const renderedLinks = this.links.map((link) => {
67
64
  return html `<li><a href="#" @click=${() => { this.viewRuleDocs(link); }}>${link}</a></li>`;
68
65
  });
@@ -1,5 +1,6 @@
1
1
  import { LitElement, TemplateResult } from "lit";
2
2
  import { ProblemItem } from "../problem-list/problem-item.js";
3
+ import { MarkerSeverity } from "monaco-editor";
3
4
  export declare class ProblemOverviewGroup extends LitElement {
4
5
  static styles: import("lit").CSSResult[];
5
6
  rank: number;
@@ -7,6 +8,7 @@ export declare class ProblemOverviewGroup extends LitElement {
7
8
  groupName: string;
8
9
  description: string;
9
10
  category: string;
11
+ severity: MarkerSeverity;
10
12
  violationPercent: number;
11
13
  problems: ProblemItem[];
12
14
  constructor();
@@ -12,6 +12,7 @@ import { OpenProblemDrawer, ProblemClicked, RuleViolationClicked } from "../../e
12
12
  import sharedCss from "../../css/shared.css.js";
13
13
  import buttonCss from "../../css/button.css.js";
14
14
  import { ProblemItem } from "../problem-list/problem-item.js";
15
+ import { MarkerSeverity } from "monaco-editor";
15
16
  let ProblemOverviewGroup = class ProblemOverviewGroup extends LitElement {
16
17
  constructor() {
17
18
  super();
@@ -64,13 +65,22 @@ let ProblemOverviewGroup = class ProblemOverviewGroup extends LitElement {
64
65
  if (!this.groupName || this.groupName === '') {
65
66
  this.groupName = 'invalid OpenAPI specification';
66
67
  }
68
+ let severity = html ``;
69
+ if (this.severity === MarkerSeverity.Error) {
70
+ clazz = "error";
71
+ severity = html `
72
+ <pb33f-model-icon color="error" size="small" icon="error"></pb33f-model-icon>
73
+ `;
74
+ pc = html `
75
+ <pb33f-percent-bar value="${this.violationPercent}" error></pb33f-percent-bar>`;
76
+ }
67
77
  return html `
68
78
  <div class="problem-overview-group">
69
79
  <div class="group-rank">
70
- <span>${this.rank}</span>
80
+ <span class="${clazz}">${this.rank}</span>
71
81
  </div>
72
82
  <div class="group-details">
73
- <span class="name ${clazz}" @click="${this.viewRuleDocs}">${this.groupName}</span>
83
+ ${severity}<span class="name ${clazz}" @click="${this.viewRuleDocs}">${this.groupName}</span>
74
84
  ${pc}
75
85
  </div>
76
86
  <div class="violations">
@@ -109,6 +119,9 @@ __decorate([
109
119
  __decorate([
110
120
  property()
111
121
  ], ProblemOverviewGroup.prototype, "category", void 0);
122
+ __decorate([
123
+ property()
124
+ ], ProblemOverviewGroup.prototype, "severity", void 0);
112
125
  __decorate([
113
126
  property({ type: Number })
114
127
  ], ProblemOverviewGroup.prototype, "violationPercent", void 0);
@@ -42,6 +42,7 @@ let ProblemsOverview = class ProblemsOverview extends LitElement {
42
42
  const group = new ProblemOverviewGroup();
43
43
  group.groupName = problem.problemObject.source;
44
44
  group.totalViolations = 1;
45
+ group.severity = problem.problemObject.severity;
45
46
  group.problems = [problem];
46
47
  problemOverviewGroups.set(rule, group);
47
48
  }
@@ -52,9 +53,14 @@ let ProblemsOverview = class ProblemsOverview extends LitElement {
52
53
  group.violationPercent = Math.round((group.totalViolations / totalViolations) * 100);
53
54
  }
54
55
  const values = Array.from(problemOverviewGroups.values());
55
- // order by violations
56
+ // order by violations, errors first.
56
57
  values.sort((a, b) => {
57
- return b.totalViolations - a.totalViolations;
58
+ if (a.severity === b.severity) {
59
+ return b.totalViolations - a.totalViolations;
60
+ }
61
+ else {
62
+ return b.severity - a.severity;
63
+ }
58
64
  });
59
65
  // stack rank.
60
66
  for (let i = 0; i < values.length; i++) {
@@ -0,0 +1,17 @@
1
+ import { LitElement } from "lit";
2
+ export declare class PixelSparks extends LitElement {
3
+ private sparkArray;
4
+ private readonly gravity;
5
+ private readonly spawnRate;
6
+ private ctx;
7
+ private canvas;
8
+ static styles: import("lit").CSSResult;
9
+ constructor();
10
+ firstUpdated(): void;
11
+ startAnimation(): void;
12
+ getRandomBetween(min: number, max: number): number;
13
+ spawnSpark(): void;
14
+ animateSparks(): void;
15
+ drawSpark(spark: any): void;
16
+ render(): import("lit-html").TemplateResult<1>;
17
+ }
@@ -0,0 +1,81 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { customElement } from "lit/decorators.js";
8
+ import { css, html, LitElement } from "lit";
9
+ let PixelSparks = class PixelSparks extends LitElement {
10
+ constructor() {
11
+ super();
12
+ this.sparkArray = [];
13
+ this.gravity = 0.0001;
14
+ this.spawnRate = 70;
15
+ }
16
+ firstUpdated() {
17
+ const canvas = this.renderRoot.querySelector('canvas');
18
+ if (canvas) {
19
+ this.canvas = canvas;
20
+ const ctx = this.canvas?.getContext('2d');
21
+ if (ctx) {
22
+ this.ctx = ctx;
23
+ }
24
+ }
25
+ this.startAnimation();
26
+ }
27
+ startAnimation() {
28
+ setInterval(() => this.spawnSpark(), 1000 / this.spawnRate);
29
+ this.animateSparks();
30
+ }
31
+ getRandomBetween(min, max) {
32
+ return Math.random() * (max - min) + min;
33
+ }
34
+ spawnSpark() {
35
+ this.sparkArray.push({
36
+ x: Math.random() * this.canvas.width,
37
+ y: -2,
38
+ size: 1,
39
+ color: Math.random() > 0.5 ? 'rgb(248, 58, 255)' : 'rgb(98, 196, 255)',
40
+ velocityY: this.getRandomBetween(0.05, 0.3),
41
+ lifetime: 300,
42
+ initialLifetime: 300,
43
+ opacity: 1
44
+ });
45
+ }
46
+ animateSparks() {
47
+ this.ctx?.clearRect(0, 0, this.canvas?.width, this.canvas?.height);
48
+ this.sparkArray = this.sparkArray.filter(spark => spark.lifetime > 0);
49
+ for (let spark of this.sparkArray) {
50
+ this.drawSpark(spark);
51
+ spark.y += spark.velocityY;
52
+ spark.velocityY += this.gravity; // Apply gravity
53
+ spark.lifetime--;
54
+ spark.opacity = spark.lifetime / spark.initialLifetime;
55
+ }
56
+ requestAnimationFrame(() => this.animateSparks());
57
+ }
58
+ drawSpark(spark) {
59
+ this.ctx.globalAlpha = spark.opacity; // Set transparency level
60
+ this.ctx.fillStyle = spark.color;
61
+ this.ctx.shadowColor = spark.color;
62
+ this.ctx.shadowBlur = 8;
63
+ this.ctx.fillRect(spark.x, spark.y, spark.size, spark.size);
64
+ this.ctx.globalAlpha = 1; // Reset alpha to default
65
+ }
66
+ render() {
67
+ return html `
68
+ <canvas width="100%" height="100%"></canvas>`;
69
+ }
70
+ };
71
+ PixelSparks.styles = css `
72
+ canvas {
73
+ width: 100%;
74
+ height: 100%;
75
+ image-rendering: pixelated; /* Ensures pixelated appearance */
76
+ }
77
+ `;
78
+ PixelSparks = __decorate([
79
+ customElement('pb33f-pixel-sparks')
80
+ ], PixelSparks);
81
+ export { PixelSparks };