@spectric/ui 0.0.7 → 0.0.9

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 (46) hide show
  1. package/README.MD +5 -28
  2. package/dist/components/Button.d.ts +14 -3
  3. package/dist/components/index.d.ts +3 -0
  4. package/dist/components/input.d.ts +5 -1
  5. package/dist/components/pagination/index.d.ts +1 -0
  6. package/dist/components/pagination/pagination.d.ts +60 -0
  7. package/dist/components/table/body.d.ts +44 -0
  8. package/dist/components/table/cell.d.ts +58 -0
  9. package/dist/components/table/header.d.ts +42 -0
  10. package/dist/components/table/index.d.ts +1 -0
  11. package/dist/components/table/table.d.ts +100 -0
  12. package/dist/components/tooltip/index.d.ts +1 -0
  13. package/dist/components/tooltip/tooltip.d.ts +95 -0
  14. package/dist/custom-elements.json +201 -7
  15. package/dist/index.es.js +2104 -1612
  16. package/dist/index.es.js.map +1 -1
  17. package/dist/index.umd.js +222 -83
  18. package/dist/index.umd.js.map +1 -1
  19. package/dist/style.css +1 -1
  20. package/package.json +1 -1
  21. package/src/components/Button.ts +23 -4
  22. package/src/components/button.css.ts +85 -2
  23. package/src/components/index.ts +4 -1
  24. package/src/components/input.css +6 -1
  25. package/src/components/input.ts +26 -5
  26. package/src/components/pagination/index.ts +1 -0
  27. package/src/components/pagination/pagination.css +10 -0
  28. package/src/components/pagination/pagination.ts +133 -0
  29. package/src/components/table/body.ts +69 -0
  30. package/src/components/table/cell.ts +133 -0
  31. package/src/components/table/header.ts +68 -0
  32. package/src/components/table/index.ts +1 -0
  33. package/src/components/table/table.css +46 -0
  34. package/src/components/table/table.ts +174 -0
  35. package/src/components/tooltip/index.ts +1 -0
  36. package/src/components/tooltip/tooltip.css +52 -0
  37. package/src/components/tooltip/tooltip.ts +228 -0
  38. package/src/docs/HTML-Vue-Python Integration.mdx +18 -0
  39. package/src/docs/React.mdx +20 -0
  40. package/src/docs/welcome.mdx +29 -0
  41. package/src/stories/Button.stories.ts +25 -2
  42. package/src/stories/fixtures/ExampleContent.ts +39 -4
  43. package/src/stories/fixtures/data.ts +20 -2
  44. package/src/stories/pagination.stories.ts +63 -0
  45. package/src/stories/table.stories.ts +88 -0
  46. package/src/stories/tooltip.stories.ts +68 -0
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- spectric-input{--input-color: var(--spectric-input-color, #f4f4f4);--border-radius: var(--spectric-border-radius, .4em);--input-bottom: var(--spectric-input-bottom, var(--spectric-button-primary, #a8a8a8));--input-bottom-focused: var(--primary, #1ea7fd);--text-on-color: var(--spectric-text-on-color, #ffffff);--text-on-color-disabled: var(--spectric-text-on-color-disabled, #8d8d8d);--text-placeholder: rgba(22, 22, 22, .4);--text-primary: var(--spectric-text-primary, #161616);--text-secondary: var(--spectric-text-secondary, #525252)}spectric-input .inputWrapper{color:var(--text-secondary)}spectric-input .inputWrapper input{box-sizing:border-box;margin:0;vertical-align:baseline;font-size:.875rem;font-weight:400;line-height:1.28572;letter-spacing:.16px;outline:transparent solid 2px;outline-offset:-2px;border:none;padding:0 1rem;background-color:var(--input-color);color:var(--text-primary, #161616);font-family:inherit;inline-size:100%;block-size:2.5rem}spectric-input .inputWrapper .inputContainer:active:after,spectric-input .inputContainer:focus-within:after{border-bottom-color:var(--input-bottom-focused);width:calc(100% - 5px);transition:width .4s ease-in-out}spectric-input .inputWrapper input:read-only{background-color:transparent;border-bottom-color:var(--border-disabled)}spectric-input .inputContainer{position:relative;border-radius:var(--border-radius);overflow:hidden}spectric-input .inputContainer:after{content:"";width:0px;transition:background-color .4s cubic-bezier(.2,0,.38,.9),border-bottom-color .4s cubic-bezier(.2,0,.38,.9);border-bottom-color:var(--input-bottom);border-bottom-style:solid;border-bottom-width:1px;position:absolute;left:2.5px;bottom:0}spectric-input #helper-text{height:18px}spectric-input spectric-button{position:absolute;right:4px;bottom:3px}spectric-query{font-family:monospace}spectric-query .autocomplete{color:var(--spectric-text-primary, #161616);border-radius:0em 0em var(--spectric-border-radius, .4em) var(--spectric-border-radius, .4em);background-color:var(--spectric-background, #ffffff);border:1px solid var(--spectric-background-hover, rgba(141, 141, 141, .12));max-height:300px;border-top:0px;margin:-18px 0 0;position:fixed;top:anchor(bottom);justify-self:anchor-center;text-align:center}spectric-query .autocomplete .optiontype{float:left;max-width:10px}spectric-query .autocomplete .label{position:absolute;right:0}spectric-query .autocomplete .option.active,spectric-query .autocomplete .option:hover{background-color:var(--spectric-background-hover, rgba(141, 141, 141, .12));border-bottom:1px solid var(--primary, #1ea7fd)}spectric-query .autocomplete .option{border-bottom:1px solid transparent;padding:8px}.query-bar-date-quick-select{display:flex;justify-content:space-evenly}
1
+ spectric-input{--input-color: var(--spectric-input-color, #f4f4f4);--border-radius: var(--spectric-border-radius, .4em);--input-bottom: var(--spectric-input-bottom, var(--spectric-button-primary, #a8a8a8));--input-bottom-focused: var(--primary, #1ea7fd);--text-on-color: var(--spectric-text-on-color, #ffffff);--text-on-color-disabled: var(--spectric-text-on-color-disabled, #8d8d8d);--text-placeholder: rgba(22, 22, 22, .4);--text-primary: var(--spectric-text-primary, #161616);--text-secondary: var(--spectric-text-secondary, #525252)}spectric-input .inputWrapper{color:var(--text-secondary)}spectric-input .inputWrapper input{box-sizing:border-box;margin:0;vertical-align:baseline;font-size:.875rem;font-weight:400;line-height:1.28572;letter-spacing:.16px;outline:transparent solid 2px;outline-offset:-2px;border:none;padding:0 1rem;background-color:var(--input-color);color:var(--text-primary, #161616);font-family:inherit;inline-size:100%;block-size:2.5rem}spectric-input .inputWrapper .inputContainer:active:after,spectric-input .inputContainer:focus-within:after{border-bottom-color:var(--input-bottom-focused);width:calc(100% - 5px);transition:width .4s ease-in-out}spectric-input .inputWrapper input:read-only{background-color:transparent;border-bottom-color:var(--border-disabled)}spectric-input .inputContainer{position:relative;border-radius:var(--border-radius);overflow:hidden}spectric-input .inputContainer:after{content:"";width:0px;transition:background-color .4s cubic-bezier(.2,0,.38,.9),border-bottom-color .4s cubic-bezier(.2,0,.38,.9);border-bottom-color:var(--input-bottom);border-bottom-style:solid;border-bottom-width:1px;position:absolute;left:2.5px;bottom:0}spectric-input #helper-text{height:18px}spectric-input[variant=password] spectric-button{position:absolute;right:4px;bottom:3px}spectric-input .checkbox{display:flex;justify-self:center}spectric-query{font-family:monospace}spectric-query .autocomplete{color:var(--spectric-text-primary, #161616);border-radius:0em 0em var(--spectric-border-radius, .4em) var(--spectric-border-radius, .4em);background-color:var(--spectric-background, #ffffff);border:1px solid var(--spectric-background-hover, rgba(141, 141, 141, .12));max-height:300px;border-top:0px;margin:-18px 0 0;position:fixed;top:anchor(bottom);justify-self:anchor-center;text-align:center}spectric-query .autocomplete .optiontype{float:left;max-width:10px}spectric-query .autocomplete .label{position:absolute;right:0}spectric-query .autocomplete .option.active,spectric-query .autocomplete .option:hover{background-color:var(--spectric-background-hover, rgba(141, 141, 141, .12));border-bottom:1px solid var(--primary, #1ea7fd)}spectric-query .autocomplete .option{border-bottom:1px solid transparent;padding:8px}.query-bar-date-quick-select{display:flex;justify-content:space-evenly}spectric-pagination .spectric-pagination-container{display:flex;justify-content:space-between;align-items:center}spectric-pagination .spectric-pagination-text{flex-grow:1;text-align:center}spectric-table{display:flex;flex-direction:column}spectric-table tr{text-align:center}spectric-table-body tr:hover{background-color:color-mix(in srgb,var(--spectric-primary, #1ea7fd),transparent 70%)}spectric-table-header{display:table-header-group;font-weight:700}spectric-table div[role=table]{display:table}spectric-table-body{display:table-row-group}spectric-table-cell{display:contents;vertical-align:middle}spectric-table-cell td{position:relative}spectric-table td:hover:has(.filterable){border:1px solid var(--spectric-primary, #1ea7fd)}spectric-table td{border:1px solid transparent}spectric-table-cell .table-cell-actions{position:absolute;display:flex;width:100%;flex-direction:row-reverse;visibility:hidden;top:-10px}spectric-table-cell td:hover .table-cell-actions{visibility:unset}.spectric-tooltip-portal{position:fixed;z-index:9999;pointer-events:none;--spectric-tooltip-background: color-mix(in srgb,var(--spectric-background-inverse,#f4f4f4) 100%,var(--spectric-primary,#1ea7fd) 90%) }.spectric-tooltip-portal .tooltip-container{display:flex;justify-content:center;align-items:center}.spectric-tooltip-portal.top .tooltip-container{flex-direction:column-reverse}.spectric-tooltip-portal.bottom .tooltip-container{flex-direction:column}.spectric-tooltip-portal.left .tooltip-container{flex-direction:row-reverse}.spectric-tooltip-portal .tooltip-content{background:var(--spectric-tooltip-background);border-radius:var(--spectric-border-radius,.4em);box-shadow:0 0 .01em .01em color-mix(in srgb,var(--spectric-background-hover,rgba(141, 141, 141, .12)) 90%,var(--spectric-text-on-color,#ffffff) 90%);padding:.2em;color:var(--spectric-text-on-color,#ffffff)}.spectric-tooltip-portal .tooltip-caret{background:var(--spectric-tooltip-background)}.spectric-tooltip-portal.top .tooltip-caret,.spectric-tooltip-portal.bottom .tooltip-caret{inline-size:.75rem;block-size:.374rem}.spectric-tooltip-portal.left .tooltip-caret,.spectric-tooltip-portal.right .tooltip-caret{inline-size:.375rem;block-size:.75rem}.spectric-tooltip-portal.top .tooltip-caret{clip-path:polygon(0 0,50% 100%,100% 0)}.spectric-tooltip-portal.bottom .tooltip-caret{clip-path:polygon(0 100%,50% 0,100% 100%)}.spectric-tooltip-portal.left .tooltip-caret{clip-path:polygon(0 0,100% 50%,0 100%)}.spectric-tooltip-portal.right .tooltip-caret{clip-path:polygon(0 50%,100% 0,100% 100%)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectric/ui",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "main": "./dist/index.es.js",
6
6
  "module": "./dist/index.es.js",
@@ -4,18 +4,24 @@ import { styleMap } from 'lit/directives/style-map.js';
4
4
  import style from './button.css';
5
5
  import { customElement, property } from 'lit/decorators.js';
6
6
  import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from './types';
7
+ import { DomRenderable } from './table';
8
+ import { TooltipPostionsTypes } from './tooltip';
7
9
 
8
10
  export enum ButtonSizes {
9
11
  large = "large",
10
12
  medium = "medium",
11
13
  small = "small",
14
+ xsmall = "xsmall",
15
+ xxsmall = "xxsmall",
16
+ tiny = "tiny"
12
17
  }
13
- type ButtonSizesTypes = `${ButtonSizes}`
18
+ export type ButtonSizesTypes = `${ButtonSizes}`
14
19
  export enum ButtonVariants {
15
20
  primary = "primary",
16
21
  secondary = "secondary",
17
- text = "text"
22
+ text = "text",
18
23
  }
24
+
19
25
  type ButtonVariantsTypes = `${ButtonVariants}`
20
26
  export interface ButtonProps {
21
27
  /** Is this the principal call to action on the page? */
@@ -28,6 +34,9 @@ export interface ButtonProps {
28
34
  /* should the button be disabled*/
29
35
  disabled: boolean;
30
36
  danger?: boolean;
37
+ icon?: boolean
38
+ tooltip?: DomRenderable
39
+ tooltipPosition?: TooltipPostionsTypes
31
40
  }
32
41
  const MODES = {
33
42
  "primary": 'spectric-button--primary',
@@ -46,14 +55,20 @@ export class SpectricButton extends LitElement implements ButtonProps {
46
55
  @property({ type: String, reflect: true })
47
56
  backgroundColor?: string | undefined;
48
57
  @property({ type: String, reflect: true })
49
- size: 'small' | 'medium' | 'large' = "large";
58
+ size: ButtonSizesTypes = "small";
50
59
  @property({ type: String, reflect: true })
51
60
  label?: string = "";
52
61
  @property({ type: Boolean, reflect: true })
53
62
  danger = false;
63
+ @property({ type: Boolean, reflect: true })
64
+ icon: boolean = false;
65
+ @property({ type: String, reflect: true })
66
+ tooltip?: DomRenderable;
67
+ @property({ type: String, reflect: true })
68
+ tooltipPosition?: TooltipPostionsTypes = "right";
54
69
  connectedCallback(): void {
55
70
  super.connectedCallback()
56
- this.addEventListener("click", this._onClick)
71
+ this.addEventListener("click", this._onClick, { capture: true })
57
72
  }
58
73
  disconnectedCallback(): void {
59
74
  super.disconnectedCallback()
@@ -66,6 +81,9 @@ export class SpectricButton extends LitElement implements ButtonProps {
66
81
  e.preventDefault()
67
82
  e.stopImmediatePropagation()
68
83
  e.stopPropagation()
84
+ if (this.disabled) {
85
+ return
86
+ }
69
87
  const options: CustomEventInit = {
70
88
  bubbles: true,
71
89
  composed: true,
@@ -77,6 +95,7 @@ export class SpectricButton extends LitElement implements ButtonProps {
77
95
  protected render(): unknown {
78
96
  const mode = MODES[this.variant] || 'spectric-button--primary';
79
97
  return html`
98
+ ${this.tooltip ? html`<spectric-tooltip .text=${this.tooltip} .position=${this.tooltipPosition || "right"} .triggerTarget=${this}></spectric-tooltip>` : null}
80
99
  <button
81
100
  type="button"
82
101
  ?disabled=${this.disabled}
@@ -22,9 +22,15 @@ export default css`
22
22
  --button-primary-hover: var(--spectric-button-primary-hover, #0050e6);
23
23
  --button-secondary-hover: var(--spectric-button-secondary-hover, #474747);
24
24
  --button-tertiary-hover: var(--spectric-button-tertiary-hover, #0050e6);
25
- --button-disabled: var(--spectric-button-disabled, #c6c6c6);
25
+ --button-disabled: var(--spectric-button-disabled, #cfcbcb4d);
26
+ }
27
+ :host([disabled]) {
28
+ cursor: not-allowed;
29
+ }
30
+
31
+ :host([disabled]) .animation{
32
+ visibility:hidden;
26
33
  }
27
- :host([disabled]) { pointer-events: none }
28
34
 
29
35
  .spectric-button {
30
36
  pointer-events:none;
@@ -78,6 +84,59 @@ export default css`
78
84
  box-shadow: 0 0 30px white inset;
79
85
  }
80
86
 
87
+ :host([icon]) .spectric-button {
88
+ padding: unset;
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: center;
92
+ -webkit-user-select: none; /* For Safari */
93
+ -moz-user-select: none; /* For Firefox */
94
+ -ms-user-select: none; /* For IE 10+ */
95
+ user-select: none; /* Standard syntax */
96
+ }
97
+
98
+
99
+
100
+ /* :host([icon][size="small"]){
101
+ height:12px;
102
+ width:12px;
103
+ }
104
+
105
+ :host([icon][size="medium"]){
106
+ height:14px;
107
+ width:14px;
108
+ }
109
+
110
+ :host([icon][size="large"]){
111
+ width: 48px;
112
+ height: 48px;
113
+ } */
114
+ :host([icon][size="tiny"]) .spectric-button{
115
+ width: 10px;
116
+ height: 10px;
117
+ }
118
+ :host([icon][size="xxsmall"]) .spectric-button{
119
+ width: 20px;
120
+ height: 20px;
121
+ }
122
+ :host([icon][size="xsmall"]) .spectric-button{
123
+ width: 28px;
124
+ height: 28px;
125
+ }
126
+ :host([icon][size="small"]) .spectric-button{
127
+ width: 34px;
128
+ height: 34px;
129
+ }
130
+ :host([icon][size="medium"]) .spectric-button{
131
+ width: 40px;
132
+ height: 40px;
133
+ }
134
+
135
+ :host([icon][size="large"]) .spectric-button{
136
+ width: 48px;
137
+ height: 48px;
138
+ }
139
+
81
140
  .spectric-button:disabled{
82
141
  cursor: not-allowed;
83
142
  pointer-events: none;
@@ -85,6 +144,11 @@ export default css`
85
144
  /* background-color:var(--button-disabled); */
86
145
  color:var(--text-on-color-disabled);
87
146
  }
147
+ .spectric-button.spectric-button--primary:disabled{
148
+
149
+ background-color:var(--button-disabled);
150
+
151
+ }
88
152
  .spectric-button:disabled .animation , :host(:disabled:hover) .animation{
89
153
  background-color: rgba(0, 0, 0, 0);
90
154
  opacity:1
@@ -145,6 +209,25 @@ opacity:1
145
209
  background-color: transparent;
146
210
  color: var(--text-secondary);
147
211
  }
212
+ .spectric-button--tiny {
213
+ font-size: 10px;
214
+ line-height: 10px;
215
+ height: 10px;
216
+ display: flex;
217
+ align-content: center;
218
+ align-items: center;
219
+ }
220
+ .spectric-button--xxsmall {
221
+ padding: 5px 6px;
222
+ font-size: 10px;
223
+ line-height: 8px;
224
+ }
225
+ .spectric-button--xsmall {
226
+ padding: 5px 8px;
227
+ font-size: 10px;
228
+ font-size: 12px;
229
+ line-height: 14px;
230
+ }
148
231
  .spectric-button--small {
149
232
  padding: 5px 10px;
150
233
  font-size: 12px;
@@ -7,4 +7,7 @@ export * from "./query_bar"
7
7
  export * from "./Panel"
8
8
  export * from "./ThemeProvider"
9
9
  export * from "./dialog"
10
- export * from "./splitview"
10
+ export * from "./splitview"
11
+ export * from "./pagination"
12
+ export * from "./table"
13
+ export * from "./tooltip"
@@ -68,8 +68,13 @@ spectric-input #helper-text {
68
68
  height: 18px;
69
69
  }
70
70
 
71
- spectric-input spectric-button {
71
+ spectric-input[variant="password"] spectric-button {
72
72
  position: absolute;
73
73
  right: 4px;
74
74
  bottom: 3px;
75
+ }
76
+
77
+ spectric-input .checkbox{
78
+ display: flex;
79
+ justify-self: center;
75
80
  }
@@ -3,6 +3,7 @@ import "./input.css"
3
3
  import { customElement, property, query } from 'lit/decorators.js';
4
4
  import { ifDefined } from 'lit/directives/if-defined.js';
5
5
  import { ReactElementWithPropsAndEvents } from './types';
6
+ import { ButtonSizesTypes } from './Button';
6
7
 
7
8
  export enum InputVariants {
8
9
  Text = 'text',
@@ -16,6 +17,7 @@ export enum InputVariants {
16
17
  file = "file",//display drop area
17
18
  hidden = "hidden",//display drop area
18
19
  password = "password",
20
+ checkbox = "checkbox"
19
21
 
20
22
  }
21
23
  type InputVariantsTypes = `${InputVariants}`
@@ -73,6 +75,9 @@ export interface InputProps {
73
75
  }
74
76
  @customElement('spectric-input')
75
77
  export class SpectricInput extends LitElement implements InputProps {
78
+ @property({ type: Boolean, reflect: true })
79
+ checked?: boolean;
80
+ size?: ButtonSizesTypes;
76
81
  //static styles?: CSSResultGroup | undefined = style;
77
82
  protected createRenderRoot(): HTMLElement | DocumentFragment {
78
83
  return this
@@ -155,7 +160,7 @@ export class SpectricInput extends LitElement implements InputProps {
155
160
  @property({ reflect: true })
156
161
  autocomplete: HTMLInputElement['autocomplete'] = "";
157
162
  get selectionStart() {
158
- if(!this._input){
163
+ if (!this._input) {
159
164
  return null
160
165
  }
161
166
  return this._input.selectionStart
@@ -187,20 +192,20 @@ export class SpectricInput extends LitElement implements InputProps {
187
192
  }
188
193
  }
189
194
  blur(): void {
190
- if(this._input){
195
+ if (this._input) {
191
196
  this._input.blur()
192
197
  }
193
198
  }
194
199
  focus(options?: FocusOptions): void {
195
- if(this._input){
200
+ if (this._input) {
196
201
  //Sometimes the input will get auto focused after a modal closes but the cursor isn't set. we need to blur then refocus to get the cursor
197
202
  this._input.blur()
198
203
  this._input.focus(options)
199
204
  }
200
205
  }
201
206
  setSelectionRange(start: number, end: number, direction: "forward" | "backward" | "none" = "none") {
202
- if(!this._input){
203
- return
207
+ if (!this._input) {
208
+ return
204
209
  }
205
210
  this._input.setSelectionRange(start, end, direction)
206
211
  }
@@ -290,6 +295,22 @@ export class SpectricInput extends LitElement implements InputProps {
290
295
 
291
296
  case InputVariants.hidden:
292
297
  return html`<input type="hidden"></input>`
298
+
299
+ case InputVariants.checkbox:
300
+
301
+ return html`
302
+ <div class="checkbox">
303
+ <spectric-button @click=${() => {
304
+ this.checked = !this.checked;
305
+ this.value = Boolean(this.checked);
306
+ console.log(this.checked, this.value)
307
+ this.dispatchEvent(new Event("change", { bubbles: true }))
308
+ }} icon size=${this.size || "xxsmall"} variant=${this.checked ? "primary" : "secondary"}>${this.checked ? '✓' : "\u00A0"}</spectric-button>
309
+ ${this.invalid || this.helperText ? html`<spectric-tooltip text=${this.invalid || this.helperText}></spectric-tooltip>` : null}
310
+ ${this.label}
311
+ </div>
312
+ </label>
313
+ `
293
314
  default:
294
315
  break;
295
316
  }
@@ -0,0 +1 @@
1
+ export * from "./pagination"
@@ -0,0 +1,10 @@
1
+ spectric-pagination .spectric-pagination-container{
2
+ display: flex;
3
+ justify-content: space-between;
4
+ align-items: center;
5
+ }
6
+ spectric-pagination .spectric-pagination-text{
7
+ flex-grow: 1;
8
+ text-align: center;
9
+
10
+ }
@@ -0,0 +1,133 @@
1
+ import { html, LitElement, PropertyValues } from 'lit';
2
+ import "../Button";
3
+ import { customElement, property, } from 'lit/decorators.js';
4
+ import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
5
+ export const PaginationElementTag = "spectric-pagination"
6
+ import "./pagination.css"
7
+ import { ButtonSizesTypes } from '../Button';
8
+ export type { PaginationProps, PaginationChangeProps, PaginationEvents }
9
+
10
+ interface PaginationChangeProps {
11
+ page: number;
12
+ pageSize: number;
13
+ }
14
+
15
+ interface PaginationProps extends PaginationChangeProps {
16
+ size: ButtonSizesTypes
17
+ totalItems?: number
18
+ pageSizeOptions?: number[]
19
+ }
20
+
21
+ console.log("Pagination")
22
+
23
+ /**
24
+ * Pagination Element
25
+ */
26
+ @customElement(PaginationElementTag)
27
+ export class PaginationElement extends LitElement implements PaginationProps {
28
+ @property({ type: Number, reflect: true })
29
+ page: number = 1;
30
+
31
+ @property({ type: Number, reflect: true })
32
+ pageSize: number = 10;
33
+
34
+ @property({ type: Number, reflect: true })
35
+ totalItems?: number;
36
+
37
+ @property({ type: Array })
38
+ pageSizeOptions = [10, 20, 50, 100, 1000];
39
+
40
+ /**
41
+ * Size of the pagination buttons
42
+ */
43
+ @property({ type: String, reflect: true })
44
+ size: ButtonSizesTypes = "xsmall"
45
+ protected createRenderRoot(): HTMLElement | DocumentFragment {
46
+ return this
47
+ }
48
+ protected updated(_changedProperties: PropertyValues): void {
49
+ if (_changedProperties.has("pageSize") && !this.pageSizeOptions.includes(this.pageSize)) {
50
+ this.pageSizeOptions = [...this.pageSizeOptions, this.pageSize].sort((a, b) => a - b)
51
+ }
52
+ }
53
+ private _handlePageUp = () => {
54
+ this.page += 1
55
+ this._emitChange()
56
+ }
57
+ private _handlePageDown = () => {
58
+ this.page -= 1
59
+ this._emitChange()
60
+ }
61
+ private _handleSizeChange = (e: any) => {
62
+ let value = parseInt(e.target.value)
63
+ this.pageSize = value
64
+ this._emitChange()
65
+ }
66
+ private _emitChange = () => {
67
+ let { page, pageSize } = this
68
+ this.dispatchEvent(new CustomEvent<PaginationChangeProps>("change", { detail: { page, pageSize } }))
69
+ }
70
+ protected render(): unknown {
71
+ let nextPage = (this.page) * this.pageSize
72
+ let nextPageDisabled = true
73
+
74
+ if (this.totalItems && nextPage < this.totalItems) {
75
+ nextPageDisabled = false
76
+ }
77
+ let pageText = ""
78
+ if (this.totalItems) {
79
+ pageText = `${this.page} of ${Math.ceil(this.totalItems / this.pageSize)}`
80
+ }
81
+ return html`
82
+ <div class="spectric-pagination-container">
83
+ <div>
84
+ <!-- TODO/FIXME Make a select component and use it for cross browser styling-->
85
+ <select @change=${this._handleSizeChange} .value=${String(this.pageSize)}>
86
+ ${this.pageSizeOptions.map(size => html`<option .value=${String(size)} class=${String(size) === String(this.pageSize) ? "selected" : ""}>${size}</option>`)}
87
+ </select>
88
+ </div>
89
+ ${this.totalItems ? html`
90
+ <div class="spectric-pagination-text">${`Items ${(this.page - 1) * this.pageSize}-${Math.min(this.page * this.pageSize, this.totalItems)} of ${this.totalItems}`}</div>
91
+ <div class="spectric-pagination-container">
92
+ <div>
93
+ ${pageText}
94
+ </div>
95
+ <div>
96
+ <spectric-button size=${this.size} ?disabled=${this.page === 1} @click=${this._handlePageDown} icon><</spectric-button>
97
+ <spectric-button size=${this.size} ?disabled=${nextPageDisabled} @click=${this._handlePageUp} icon>></spectric-button>
98
+ </div>
99
+ </div>
100
+ `: null}
101
+ </div>
102
+ `;
103
+ }
104
+ }
105
+
106
+ interface PaginationEvents {
107
+ 'change': (event: CustomEvent<PaginationChangeProps>) => void;
108
+ }
109
+
110
+ declare global {
111
+ interface HTMLElementTagNameMap {
112
+ [PaginationElementTag]: HTMLElementTagWithEvents<PaginationElement, PaginationEvents>
113
+
114
+ }
115
+ namespace JSX {
116
+ interface IntrinsicElements {
117
+ /**
118
+ * @see {@link DialogElement}
119
+ */
120
+ [PaginationElementTag]: ReactElementWithPropsAndEvents<PaginationElement, PaginationProps, PaginationEvents>;
121
+ }
122
+ }
123
+ namespace React {
124
+ namespace JSX {
125
+ interface IntrinsicElements {
126
+ /**
127
+ * @see {@link DialogElement}
128
+ */
129
+ [PaginationElementTag]: ReactElementWithPropsAndEvents<PaginationElement, PaginationProps, PaginationEvents>
130
+ }
131
+ }
132
+ }
133
+ }
@@ -0,0 +1,69 @@
1
+ import { html, LitElement } from 'lit';
2
+ import { customElement, property, } from 'lit/decorators.js';
3
+ import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
4
+ export const TableBodyElementTag = "spectric-table-body"
5
+ import "./cell"
6
+ import { ColumnSettings, TableElement } from './table';
7
+
8
+ interface BodyProps<T> {
9
+ columns: ColumnSettings<T>[]
10
+ data: T[]
11
+ }
12
+
13
+
14
+ /**
15
+ * Table Body Element
16
+ */
17
+ @customElement(TableBodyElementTag)
18
+ export class TableBodyElement<T> extends LitElement implements BodyProps<T> {
19
+ @property({ type: Array, attribute: false })
20
+ data: T[] = [];
21
+ @property({ type: Array, attribute: false })
22
+ columns: ColumnSettings<T>[] = [];
23
+ table!: TableElement<T>
24
+ protected createRenderRoot(): HTMLElement | DocumentFragment {
25
+ return this
26
+ }
27
+ protected render(): unknown {
28
+ return html`
29
+ <body>
30
+ ${this.data.map((row: any) => {
31
+ return html`<tr>${this.columns.map(col => {
32
+ return html`<spectric-table-cell .column=${col} .row=${row} .columns=${this.columns}></spectric-table-cell>`
33
+ })}</tr>`
34
+ })}
35
+ </body>
36
+ `
37
+
38
+ }
39
+
40
+ }
41
+
42
+ interface TableBodyEvents {
43
+ //'sort': (event: CustomEvent<ColumnSettings<any>>) => void; //TODO sort events
44
+ }
45
+
46
+ declare global {
47
+ interface HTMLElementTagNameMap {
48
+ [TableBodyElementTag]: HTMLElementTagWithEvents<TableBodyElement<any>, TableBodyEvents>
49
+
50
+ }
51
+ namespace JSX {
52
+ interface IntrinsicElements {
53
+ /**
54
+ * @see {@link DialogElement}
55
+ */
56
+ [TableBodyElementTag]: ReactElementWithPropsAndEvents<TableBodyElement<any>, BodyProps<any>, TableBodyEvents>;
57
+ }
58
+ }
59
+ namespace React {
60
+ namespace JSX {
61
+ interface IntrinsicElements {
62
+ /**
63
+ * @see {@link DialogElement}
64
+ */
65
+ [TableBodyElementTag]: ReactElementWithPropsAndEvents<TableBodyElement<any>, BodyProps<any>, TableBodyEvents>
66
+ }
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,133 @@
1
+ import { html, LitElement, PropertyValues } from 'lit';
2
+ import { customElement, property, query, } from 'lit/decorators.js';
3
+ import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
4
+ export const TableCellElementTag = "spectric-table-cell"
5
+ import { ColumnSettings, TableElement } from './table';
6
+
7
+ interface CellProps<T> {
8
+ column: ColumnSettings<T>
9
+ row: T
10
+ }
11
+
12
+ export type FilterEvent<T> = {
13
+ value?: T,
14
+ include: boolean
15
+ column: ColumnSettings<T>
16
+ row: T
17
+ }
18
+
19
+ /**
20
+ * Pagination Element
21
+ */
22
+ @customElement(TableCellElementTag)
23
+ export class TableCellElement<T> extends LitElement implements CellProps<T> {
24
+ @property({ type: Object, attribute: false })
25
+ row!: T;
26
+ @property({ type: Object, attribute: false })
27
+ column!: ColumnSettings<T>;
28
+ columns!: ColumnSettings<T>[];
29
+ table!: TableElement<T>
30
+ styleRules: CSSStyleDeclaration;
31
+ @query("td")
32
+ td!: HTMLTableCellElement
33
+ constructor() {
34
+ super()
35
+ this.styleRules = document.createElement('span').style;
36
+ }
37
+ protected updated(_changedProperties: PropertyValues): void {
38
+ Object.assign(this.td.style, this.styleRules)
39
+ }
40
+ protected createRenderRoot(): HTMLElement | DocumentFragment {
41
+ return this
42
+ }
43
+ _handleFilterOut = () => {
44
+ let value = undefined;
45
+ if (this.column.key && typeof this.row === "object") {
46
+ value = (this.row as Record<any, any>)[this.column.key]
47
+ }
48
+ this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter", {
49
+ composed: true,
50
+ bubbles: true,
51
+ detail: {
52
+ include: false,
53
+ row: this.row,
54
+ value,
55
+ column: this.column
56
+ }
57
+ }))
58
+ }
59
+ _handleFilterFor = () => {
60
+ let value = undefined;
61
+ if (this.column.key && typeof this.row === "object") {
62
+ value = (this.row as Record<any, any>)[this.column.key]
63
+ }
64
+ this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter", {
65
+ composed: true,
66
+ bubbles: true,
67
+ detail: {
68
+ include: true,
69
+ row: this.row,
70
+ value,
71
+ column: this.column
72
+ }
73
+ }))
74
+ }
75
+ protected render(): unknown {
76
+ let rendered
77
+ if (this.column.render) {
78
+ rendered = this.column.render(this.row, this.table)
79
+ } else if (this.column.key && typeof this.row === 'object') {
80
+ rendered = (this.row as Record<any, any>)[this.column.key]
81
+ } else {
82
+ rendered = html`error`
83
+ }
84
+ let classes = ["cell-contents"]
85
+ if (this.column.filterable) {
86
+ classes.push("filterable")
87
+ }
88
+ let filterButtons = html`<div class="table-cell-actions">
89
+ <spectric-button @click=${this._handleFilterOut} size="tiny" variant="text" icon tooltip="Filter Out Value">-</spectric-button>
90
+ <spectric-button @click=${this._handleFilterFor} size="tiny" variant="text" icon tooltip="Filter For Value">+</spectric-button></div>`
91
+ this.styleRules = {
92
+ ...this.styleRules,
93
+ width: this.column.width ? this.column.width + "px" : "",
94
+ whiteSpace: this.column.whiteSpace || ""
95
+ }
96
+ return html`
97
+ <td>
98
+ ${this.column.filterable ? filterButtons : null}
99
+ <div class=${classes.join(" ")}>${rendered}</div>
100
+ </td>
101
+ `
102
+ }
103
+
104
+ }
105
+
106
+ interface TableBodyEvents {
107
+ 'filter': (event: CustomEvent<ColumnSettings<any>>) => void; //TODO filter events
108
+ }
109
+
110
+ declare global {
111
+ interface HTMLElementTagNameMap {
112
+ [TableCellElementTag]: HTMLElementTagWithEvents<TableCellElement<any>, TableBodyEvents>
113
+
114
+ }
115
+ namespace JSX {
116
+ interface IntrinsicElements {
117
+ /**
118
+ * @see {@link DialogElement}
119
+ */
120
+ [TableCellElementTag]: ReactElementWithPropsAndEvents<TableCellElement<any>, CellProps<any>, TableBodyEvents>;
121
+ }
122
+ }
123
+ namespace React {
124
+ namespace JSX {
125
+ interface IntrinsicElements {
126
+ /**
127
+ * @see {@link DialogElement}
128
+ */
129
+ [TableCellElementTag]: ReactElementWithPropsAndEvents<TableCellElement<any>, CellProps<any>, TableBodyEvents>
130
+ }
131
+ }
132
+ }
133
+ }