@spectric/ui 0.0.8 → 0.0.10

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 (39) hide show
  1. package/README.MD +5 -28
  2. package/dist/components/Button.d.ts +8 -2
  3. package/dist/components/index.d.ts +1 -0
  4. package/dist/components/input.d.ts +5 -1
  5. package/dist/components/query_bar/QueryBar.d.ts +4 -4
  6. package/dist/components/table/body.d.ts +1 -1
  7. package/dist/components/table/cell.d.ts +6 -1
  8. package/dist/components/table/table.d.ts +13 -29
  9. package/dist/components/tooltip/index.d.ts +1 -0
  10. package/dist/components/tooltip/tooltip.d.ts +95 -0
  11. package/dist/custom-elements.json +103 -8
  12. package/dist/index.es.js +1833 -1646
  13. package/dist/index.es.js.map +1 -1
  14. package/dist/index.umd.js +116 -83
  15. package/dist/index.umd.js.map +1 -1
  16. package/dist/style.css +1 -1
  17. package/package.json +1 -1
  18. package/src/components/Button.ts +14 -3
  19. package/src/components/button.css.ts +19 -2
  20. package/src/components/index.ts +2 -1
  21. package/src/components/input.css +6 -1
  22. package/src/components/input.ts +26 -5
  23. package/src/components/pagination/pagination.ts +3 -3
  24. package/src/components/query_bar/QueryBar.ts +6 -6
  25. package/src/components/table/body.ts +2 -2
  26. package/src/components/table/cell.ts +35 -8
  27. package/src/components/table/table.css +12 -2
  28. package/src/components/table/table.ts +48 -31
  29. package/src/components/tooltip/index.ts +1 -0
  30. package/src/components/tooltip/tooltip.css +52 -0
  31. package/src/components/tooltip/tooltip.ts +228 -0
  32. package/src/docs/HTML-Vue-Python Integration.mdx +18 -0
  33. package/src/docs/React.mdx +20 -0
  34. package/src/docs/welcome.mdx +29 -0
  35. package/src/stories/Button.stories.ts +22 -0
  36. package/src/stories/fixtures/ExampleContent.ts +39 -4
  37. package/src/stories/fixtures/data.ts +22 -2
  38. package/src/stories/table.stories.ts +29 -21
  39. 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}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-header{display:table-header-group}spectric-table div[role=table]{display:table}spectric-table-body{display:table-row-group}spectric-table-cell{display:contents}spectric-table-cell td{position:relative}spectric-table .filterable{padding-top:10px}spectric-table-cell .table-cell-actions{position:absolute;display:flex;width:100%;flex-direction:row-reverse;visibility:hidden}spectric-table-cell td:hover .table-cell-actions{visibility:unset}
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.8",
3
+ "version": "0.0.10",
4
4
  "type": "module",
5
5
  "main": "./dist/index.es.js",
6
6
  "module": "./dist/index.es.js",
@@ -4,6 +4,8 @@ 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",
@@ -23,16 +25,18 @@ export enum ButtonVariants {
23
25
  type ButtonVariantsTypes = `${ButtonVariants}`
24
26
  export interface ButtonProps {
25
27
  /** Is this the principal call to action on the page? */
26
- variant: ButtonVariantsTypes;
28
+ variant?: ButtonVariantsTypes;
27
29
  /** What background color to use */
28
30
  backgroundColor?: string;
29
31
  /** How large should the button be? */
30
32
  size: ButtonSizesTypes;
31
33
  label?: string,
32
34
  /* should the button be disabled*/
33
- disabled: boolean;
35
+ disabled?: boolean;
34
36
  danger?: boolean;
35
37
  icon?: boolean
38
+ tooltip?: DomRenderable
39
+ tooltipPosition?: TooltipPostionsTypes
36
40
  }
37
41
  const MODES = {
38
42
  "primary": 'spectric-button--primary',
@@ -58,7 +62,10 @@ export class SpectricButton extends LitElement implements ButtonProps {
58
62
  danger = false;
59
63
  @property({ type: Boolean, reflect: true })
60
64
  icon: boolean = false;
61
-
65
+ @property({ type: String, reflect: true })
66
+ tooltip?: DomRenderable;
67
+ @property({ type: String, reflect: true })
68
+ tooltipPosition?: TooltipPostionsTypes = "right";
62
69
  connectedCallback(): void {
63
70
  super.connectedCallback()
64
71
  this.addEventListener("click", this._onClick, { capture: true })
@@ -74,6 +81,9 @@ export class SpectricButton extends LitElement implements ButtonProps {
74
81
  e.preventDefault()
75
82
  e.stopImmediatePropagation()
76
83
  e.stopPropagation()
84
+ if (this.disabled) {
85
+ return
86
+ }
77
87
  const options: CustomEventInit = {
78
88
  bubbles: true,
79
89
  composed: true,
@@ -85,6 +95,7 @@ export class SpectricButton extends LitElement implements ButtonProps {
85
95
  protected render(): unknown {
86
96
  const mode = MODES[this.variant] || 'spectric-button--primary';
87
97
  return html`
98
+ ${this.tooltip ? html`<spectric-tooltip .text=${this.tooltip} .position=${this.tooltipPosition || "right"} .triggerTarget=${this}></spectric-tooltip>` : null}
88
99
  <button
89
100
  type="button"
90
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;
@@ -83,8 +89,14 @@ export default css`
83
89
  display: flex;
84
90
  align-items: center;
85
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 */
86
96
  }
87
97
 
98
+
99
+
88
100
  /* :host([icon][size="small"]){
89
101
  height:12px;
90
102
  width:12px;
@@ -132,6 +144,11 @@ export default css`
132
144
  /* background-color:var(--button-disabled); */
133
145
  color:var(--text-on-color-disabled);
134
146
  }
147
+ .spectric-button.spectric-button--primary:disabled{
148
+
149
+ background-color:var(--button-disabled);
150
+
151
+ }
135
152
  .spectric-button:disabled .animation , :host(:disabled:hover) .animation{
136
153
  background-color: rgba(0, 0, 0, 0);
137
154
  opacity:1
@@ -9,4 +9,5 @@ export * from "./ThemeProvider"
9
9
  export * from "./dialog"
10
10
  export * from "./splitview"
11
11
  export * from "./pagination"
12
- export * from "./table"
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
  }
@@ -41,7 +41,7 @@ export class PaginationElement extends LitElement implements PaginationProps {
41
41
  * Size of the pagination buttons
42
42
  */
43
43
  @property({ type: String, reflect: true })
44
- size: ButtonSizesTypes = "small"
44
+ size: ButtonSizesTypes = "xsmall"
45
45
  protected createRenderRoot(): HTMLElement | DocumentFragment {
46
46
  return this
47
47
  }
@@ -93,8 +93,8 @@ export class PaginationElement extends LitElement implements PaginationProps {
93
93
  ${pageText}
94
94
  </div>
95
95
  <div>
96
- <spectric-button size=${this.size} ?disabled=${this.page === 1} @click=${this._handlePageDown}><</spectric-button>
97
- <spectric-button size=${this.size} ?disabled=${nextPageDisabled} @click=${this._handlePageUp}>></spectric-button>
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
98
  </div>
99
99
  </div>
100
100
  `: null}
@@ -39,7 +39,7 @@ export interface IQueryProps {
39
39
  /**
40
40
  * The output of the query in a specific format
41
41
  */
42
- outputLanguage: SupportedLanguagesTypes;
42
+ outputLanguage?: SupportedLanguagesTypes;
43
43
  /**
44
44
  * The output of the query
45
45
  */
@@ -47,16 +47,16 @@ export interface IQueryProps {
47
47
  /**
48
48
  * Fields that are used for the auto complete
49
49
  */
50
- fields: FieldTypes[];
50
+ fields?: FieldTypes[];
51
51
  /**
52
52
  * Callback that will provide values for specific fields
53
53
  */
54
- getValuesForField: (field: string, text: string) => Promise<string[]>;
54
+ getValuesForField?: (field: string, text: string) => Promise<string[]>;
55
55
 
56
56
  /**
57
57
  * Input placeholder
58
58
  */
59
- placeholder: string;
59
+ placeholder?: string;
60
60
  }
61
61
  type LabelValue = {
62
62
  label?: string;
@@ -133,7 +133,7 @@ export class SpectricQuery extends LitElement implements IQueryProps {
133
133
  protected _input!: SpectricInput;
134
134
  _parseQuery = (e: InputEvent | undefined = undefined) => {
135
135
  let ast;
136
- if(e && e?.currentTarget && (e.currentTarget as HTMLInputElement).value){
136
+ if (e && e?.currentTarget && (e.currentTarget as HTMLInputElement).value) {
137
137
  this.value = (e.currentTarget as HTMLInputElement).value
138
138
  }
139
139
  if (this.value == "") {
@@ -293,7 +293,7 @@ export class SpectricQuery extends LitElement implements IQueryProps {
293
293
  let value = await completion.onSelect()
294
294
  if (value !== undefined) {
295
295
  this.value += value
296
- setTimeout(()=>{this._input.focus();})
296
+ setTimeout(() => { this._input.focus(); })
297
297
  }
298
298
  }
299
299
  this.completionIndex = 0;
@@ -12,7 +12,7 @@ interface BodyProps<T> {
12
12
 
13
13
 
14
14
  /**
15
- * Pagination Element
15
+ * Table Body Element
16
16
  */
17
17
  @customElement(TableBodyElementTag)
18
18
  export class TableBodyElement<T> extends LitElement implements BodyProps<T> {
@@ -29,7 +29,7 @@ export class TableBodyElement<T> extends LitElement implements BodyProps<T> {
29
29
  <body>
30
30
  ${this.data.map((row: any) => {
31
31
  return html`<tr>${this.columns.map(col => {
32
- return html`<spectric-table-cell .column=${col} .row=${row}></spectric-table-cell>`
32
+ return html`<spectric-table-cell .column=${col} .row=${row} .columns=${this.columns}></spectric-table-cell>`
33
33
  })}</tr>`
34
34
  })}
35
35
  </body>
@@ -1,5 +1,5 @@
1
- import { html, LitElement } from 'lit';
2
- import { customElement, property, } from 'lit/decorators.js';
1
+ import { html, LitElement, PropertyValues } from 'lit';
2
+ import { customElement, property, query, } from 'lit/decorators.js';
3
3
  import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
4
4
  export const TableCellElementTag = "spectric-table-cell"
5
5
  import { ColumnSettings, TableElement } from './table';
@@ -25,14 +25,25 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
25
25
  row!: T;
26
26
  @property({ type: Object, attribute: false })
27
27
  column!: ColumnSettings<T>;
28
+ columns!: ColumnSettings<T>[];
28
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
+ }
29
40
  protected createRenderRoot(): HTMLElement | DocumentFragment {
30
41
  return this
31
42
  }
32
43
  _handleFilterOut = () => {
33
44
  let value = undefined;
34
45
  if (this.column.key && typeof this.row === "object") {
35
- value = (this.row as Record<any, any>)[this.column.key]
46
+ value = getValue(this.row as Record<any, any>, this.column.key)
36
47
  }
37
48
  this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter", {
38
49
  composed: true,
@@ -48,7 +59,7 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
48
59
  _handleFilterFor = () => {
49
60
  let value = undefined;
50
61
  if (this.column.key && typeof this.row === "object") {
51
- value = (this.row as Record<any, any>)[this.column.key]
62
+ value = getValue(this.row as Record<any, any>, this.column.key)
52
63
  }
53
64
  this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter", {
54
65
  composed: true,
@@ -66,7 +77,8 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
66
77
  if (this.column.render) {
67
78
  rendered = this.column.render(this.row, this.table)
68
79
  } else if (this.column.key && typeof this.row === 'object') {
69
- rendered = (this.row as Record<any, any>)[this.column.key]
80
+
81
+ rendered = getValue(this.row as any, this.column.key)
70
82
  } else {
71
83
  rendered = html`error`
72
84
  }
@@ -74,9 +86,14 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
74
86
  if (this.column.filterable) {
75
87
  classes.push("filterable")
76
88
  }
77
- let filterButtons = html`<div class="table-cell-actions"><spectric-button @click=${this._handleFilterOut} size="tiny" variant="text" icon>-</spectric-button><spectric-button @click=${this._handleFilterFor} size="tiny" variant="text" icon>+</spectric-button></div>`
78
-
79
-
89
+ let filterButtons = html`<div class="table-cell-actions">
90
+ <spectric-button @click=${this._handleFilterOut} size="tiny" variant="text" icon tooltip="Filter Out Value">-</spectric-button>
91
+ <spectric-button @click=${this._handleFilterFor} size="tiny" variant="text" icon tooltip="Filter For Value">+</spectric-button></div>`
92
+ this.styleRules = {
93
+ ...this.styleRules,
94
+ width: this.column.width ? this.column.width + "px" : "",
95
+ whiteSpace: this.column.whiteSpace || ""
96
+ }
80
97
  return html`
81
98
  <td>
82
99
  ${this.column.filterable ? filterButtons : null}
@@ -115,3 +132,13 @@ declare global {
115
132
  }
116
133
  }
117
134
  }
135
+
136
+
137
+ const getValue = (context: Record<string, any>, key: string) => {
138
+ let path = key.split(".")
139
+ let value = context[path[0]]
140
+ if (path.length > 1) {
141
+ value = getValue(value, path.slice(1).join("."))
142
+ }
143
+ return value
144
+ }
@@ -6,8 +6,12 @@ spectric-table tr{
6
6
  text-align: center;
7
7
  }
8
8
 
9
+ spectric-table-body tr:hover{
10
+ background-color: color-mix(in srgb, var(--spectric-primary, #1ea7fd), transparent 70%)
11
+ }
9
12
  spectric-table-header{
10
13
  display: table-header-group;
14
+ font-weight: bold;
11
15
  }
12
16
  spectric-table div[role="table"]{
13
17
  display: table;
@@ -17,12 +21,17 @@ spectric-table-body {
17
21
  }
18
22
  spectric-table-cell{
19
23
  display: contents;
24
+ vertical-align: middle;
20
25
  }
21
26
  spectric-table-cell td{
22
27
  position: relative;
23
28
  }
24
- spectric-table .filterable {
25
- padding-top: 10px;
29
+
30
+ spectric-table td:hover:has(.filterable) {
31
+ border: 1px solid var(--spectric-primary, #1ea7fd);
32
+ }
33
+ spectric-table td {
34
+ border: 1px solid transparent;
26
35
  }
27
36
  spectric-table-cell .table-cell-actions{
28
37
  position: absolute;
@@ -30,6 +39,7 @@ spectric-table-cell .table-cell-actions{
30
39
  width: 100%;
31
40
  flex-direction: row-reverse;
32
41
  visibility: hidden;
42
+ top: -10px;
33
43
  }
34
44
  spectric-table-cell td:hover .table-cell-actions{
35
45
  visibility: unset;
@@ -2,7 +2,7 @@ import { html, LitElement, TemplateResult } from 'lit';
2
2
  import "../pagination";
3
3
  import "./header"
4
4
  import "./body"
5
- import { customElement, property, } from 'lit/decorators.js';
5
+ import { customElement, property, state, } from 'lit/decorators.js';
6
6
  import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
7
7
  import "./table.css"
8
8
  export const TableElementTag = "spectric-table"
@@ -14,49 +14,30 @@ export type { TableProps, TableEvents }
14
14
  export type DomRenderable = HTMLElement | TemplateResult | string | number | null
15
15
 
16
16
  export type ColumnSettings<T> = {
17
+ width?: number
18
+ whiteSpace?: "nowrap";
17
19
  hidden?: boolean
18
20
  sortable?: boolean
19
21
  filterable?: boolean
20
- title?: string
22
+ title?: DomRenderable
21
23
  key?: string
22
24
  render?: (row: T, table: TableElement<T>) => DomRenderable
23
25
  }
26
+ type TableSelectOptions = "multi" | "single"
24
27
  interface TableProps<T> {
25
28
  pagination?: PaginationProps
26
29
  columns: ColumnSettings<T>[]
27
30
  data: T[]
31
+ select?: TableSelectOptions
28
32
  }
29
33
 
34
+ type DomEvent<T> = Event & {
35
+ target: T
36
+ }
30
37
  /**
31
- * Table Element
32
- *
33
- * The table element is a bit more complex and the column settings and data can only be set through the properties
34
- *
35
- *
36
- * React
37
- *
38
- * ``` tsx
39
- * <spectric-table data={[{col1:1}]} columns={[{key:"col1",}]} ></spectric-table>
40
- * ```
41
- *
42
- * Javascript
43
- *
44
- * ``` js
45
- * table = document.createElement("spectric-table")
46
- * table.data = [{col1:1}]
47
- * table.columns = [{key:"col1",}]
48
- * ```
38
+ * React example
39
+ * <iframe width="100%" height="400px" src="https://stackblitz.com/edit/react-ts-2ue7azag?ctl=1&embed=1&file=App.tsx&hideExplorer=1&hideNavigation=1"/>
49
40
  *
50
- * HTML
51
- *
52
- * ``` html
53
- * <spectric-table id="table"></spectric-table>
54
- * <script>
55
- * document.querySelector("#table")
56
- * table.data = [{col1:1}]
57
- * table.columns = [{key:"col1",}]
58
- * </script>
59
- * ```
60
41
  */
61
42
  @customElement(TableElementTag)
62
43
  export class TableElement<T> extends LitElement implements TableProps<T> {
@@ -66,6 +47,8 @@ export class TableElement<T> extends LitElement implements TableProps<T> {
66
47
  pagination?: PaginationProps | undefined;
67
48
  @property({ attribute: false })
68
49
  columns: ColumnSettings<T>[] = [];
50
+ @property({ type: String, reflect: false })
51
+ select?: TableSelectOptions;
69
52
  private _handlePaginationChange = (e: CustomEvent<PaginationChangeProps>) => {
70
53
  e.preventDefault()
71
54
  e.stopPropagation()
@@ -84,12 +67,46 @@ export class TableElement<T> extends LitElement implements TableProps<T> {
84
67
  //This is only here to document events that bubble up from lower components
85
68
  this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter"))
86
69
  }
70
+ @state()
71
+ selected: T[] = [];
87
72
  protected createRenderRoot(): HTMLElement | DocumentFragment {
88
73
  return this
89
74
  }
90
-
75
+ _handleSelectAllChange = (e: DomEvent<HTMLInputElement>) => {
76
+ e.stopPropagation()
77
+ if (e.target.checked) {
78
+ this.selected = [...this.data]
79
+ } else {
80
+ this.selected = []
81
+ }
82
+ this.dispatchEvent(new CustomEvent("select", { detail: this.selected }))
83
+ }
91
84
  protected render(): unknown {
92
85
  let columns = this.columns.filter(column => !column.hidden)
86
+ if (this.select) {
87
+ columns.unshift({
88
+ title: this.select === "multi" ? html`<spectric-input variant="checkbox" @change=${this._handleSelectAllChange} .helperText=${"Select All"}></spectric-input>` : null,
89
+ render: (row) => {
90
+ return html`<spectric-input variant="checkbox" .checked=${this.selected.includes(row)} @change=${(e: DomEvent<HTMLInputElement>) => {
91
+ e.stopPropagation()
92
+ if (this.select === "single") {
93
+ this.selected = []
94
+ }
95
+ if (e.target.checked) {
96
+ this.selected.push(row)
97
+ this.dispatchEvent(new CustomEvent("select", { detail: this.selected }))
98
+ } else {
99
+ let index = this.selected.findIndex(value => value === row)
100
+ if (index !== -1) {
101
+ this.selected.splice(index, 1)
102
+ this.dispatchEvent(new CustomEvent("select", { detail: this.selected }))
103
+ }
104
+ }
105
+ }}></spectric-input>`
106
+ }
107
+ })
108
+ }
109
+
93
110
  return html`
94
111
  <div role="table">
95
112
  <spectric-table-header .columns=${columns}></spectric-table-header>
@@ -0,0 +1 @@
1
+ export * from "./tooltip"
@@ -0,0 +1,52 @@
1
+ .spectric-tooltip-portal{
2
+ position: fixed;
3
+ z-index: 9999;
4
+ pointer-events: none;
5
+ --spectric-tooltip-background: color-mix(in srgb,var(--spectric-background-inverse,#f4f4f4) 100%,var(--spectric-primary,#1ea7fd) 90%)
6
+ }
7
+ .spectric-tooltip-portal .tooltip-container{
8
+ display: flex;
9
+ justify-content: center;
10
+ align-items: center;
11
+ }
12
+ .spectric-tooltip-portal.top .tooltip-container{
13
+ flex-direction: column-reverse;
14
+ }
15
+ .spectric-tooltip-portal.bottom .tooltip-container{
16
+ flex-direction: column;
17
+ }
18
+ .spectric-tooltip-portal.left .tooltip-container{
19
+ flex-direction: row-reverse;
20
+ }
21
+
22
+ .spectric-tooltip-portal .tooltip-content{
23
+ background: var(--spectric-tooltip-background);
24
+ border-radius: var(--spectric-border-radius,.4em);
25
+ box-shadow: 0 0 .01em .01em color-mix(in srgb, var(--spectric-background-hover,rgba(141, 141, 141, 0.12)) 90%, var(--spectric-text-on-color,#ffffff) 90%);
26
+ padding: .2em;
27
+ color:var(--spectric-text-on-color,#ffffff);
28
+ }
29
+
30
+ .spectric-tooltip-portal .tooltip-caret{
31
+ background:var(--spectric-tooltip-background);
32
+ }
33
+ .spectric-tooltip-portal.top .tooltip-caret,.spectric-tooltip-portal.bottom .tooltip-caret{
34
+ inline-size: .75rem;
35
+ block-size: .374rem;
36
+ }
37
+ .spectric-tooltip-portal.left .tooltip-caret,.spectric-tooltip-portal.right .tooltip-caret{
38
+ inline-size: .375rem;
39
+ block-size: .75rem;
40
+ }
41
+ .spectric-tooltip-portal.top .tooltip-caret{
42
+ clip-path: polygon(0 0,50% 100%,100% 0);
43
+ }
44
+ .spectric-tooltip-portal.bottom .tooltip-caret{
45
+ clip-path: polygon(0 100%,50% 0,100% 100%);
46
+ }
47
+ .spectric-tooltip-portal.left .tooltip-caret{
48
+ clip-path: polygon(0 0,100% 50%,0 100%);
49
+ }
50
+ .spectric-tooltip-portal.right .tooltip-caret{
51
+ clip-path: polygon(0 50% ,100% 0, 100% 100%);
52
+ }