@stonecrop/atable 0.2.38 → 0.2.40

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.
@@ -6,7 +6,7 @@ import ATable from '@/components/ATable.vue';
6
6
  import ATableHeader from '@/components/ATableHeader.vue';
7
7
  import ATableModal from '@/components/ATableModal.vue';
8
8
  import TableDataStore from './components';
9
- export type { CellFormatContext, TableColumn, TableConfig, TableDisplay, TableRow, TableModal } from '@/types';
9
+ export type { CellContext, TableColumn, TableConfig, TableDisplay, TableRow, TableModal } from '@/types';
10
10
  /**
11
11
  * Install all ATable components
12
12
  * @param app - Vue app instance
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,OAAO,KAAK,MAAM,wBAAwB,CAAA;AAC1C,OAAO,aAAa,MAAM,gCAAgC,CAAA;AAC1D,OAAO,IAAI,MAAM,uBAAuB,CAAA;AACxC,OAAO,MAAM,MAAM,yBAAyB,CAAA;AAC5C,OAAO,YAAY,MAAM,+BAA+B,CAAA;AACxD,OAAO,WAAW,MAAM,8BAA8B,CAAA;AACtD,OAAO,cAAc,MAAM,cAAc,CAAA;AACzC,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAE9G;;;;GAIG;AACH,iBAAS,OAAO,CAAC,GAAG,EAAE,GAAG,QAOxB;AAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,OAAO,KAAK,MAAM,wBAAwB,CAAA;AAC1C,OAAO,aAAa,MAAM,gCAAgC,CAAA;AAC1D,OAAO,IAAI,MAAM,uBAAuB,CAAA;AACxC,OAAO,MAAM,MAAM,yBAAyB,CAAA;AAC5C,OAAO,YAAY,MAAM,+BAA+B,CAAA;AACxD,OAAO,WAAW,MAAM,8BAA8B,CAAA;AACtD,OAAO,cAAc,MAAM,cAAc,CAAA;AACzC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAExG;;;;GAIG;AACH,iBAAS,OAAO,CAAC,GAAG,EAAE,GAAG,QAOxB;AAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,CAAA"}
@@ -6,14 +6,15 @@ export type TableColumn = {
6
6
  label?: string;
7
7
  type?: string;
8
8
  width?: string;
9
+ pinned?: boolean;
9
10
  cellComponent?: string;
10
11
  cellComponentProps?: Record<string, any>;
11
- modalComponent?: string;
12
- modalComponentProps?: Record<string, any>;
13
- format?: string | ((value: any, context?: CellFormatContext) => string);
12
+ modalComponent?: string | ((context?: CellContext) => string);
13
+ modalComponentExtraProps?: Record<string, any>;
14
+ format?: string | ((value: any, context?: CellContext) => string);
14
15
  mask?: (value: any) => any;
15
16
  };
16
- export type CellFormatContext = {
17
+ export type CellContext = {
17
18
  row: TableRow;
18
19
  column: TableColumn;
19
20
  table: TableDataStore['table'];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,cAAc,CAAA;AAEzC,MAAM,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IAEZ,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACxC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAEzC,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,iBAAiB,KAAK,MAAM,CAAC,CAAA;IACvE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC/B,GAAG,EAAE,QAAQ,CAAA;IACb,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,gBAAgB,CAAA;IACzC,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACpC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,cAAc,CAAA;AAEzC,MAAM,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IAEZ,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACxC,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,WAAW,KAAK,MAAM,CAAC,CAAA;IAC7D,wBAAwB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE9C,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,MAAM,CAAC,CAAA;IACjE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACzB,GAAG,EAAE,QAAQ,CAAA;IACb,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,gBAAgB,CAAA;IACzC,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACpC,CAAA"}
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- @import"https://fonts.googleapis.com/css2?family=Arimo:ital,wght@0,400..700;1,400..700&display=swap";.list-index{color:var(--header-text-color);font-weight:700;padding-left:var(--atable-row-padding);padding-right:1em;text-align:center;-webkit-user-select:none;user-select:none;width:var(--20b4541e);max-width:var(--20b4541e)}.atable #header-index{width:var(--20b4541e);max-width:var(--20b4541e)}.list-index{color:var(--header-text-color);font-weight:700;padding-left:var(--atable-row-padding);padding-right:1em;text-align:center;-webkit-user-select:none;user-select:none;width:var(--d266282a);max-width:var(--d266282a)}.atable #header-index{width:var(--d266282a);max-width:var(--d266282a)}.list-index{color:var(--header-text-color);font-weight:700;padding-left:var(--atable-row-padding);padding-right:1em;text-align:center;-webkit-user-select:none;user-select:none;width:var(--aa18a430);max-width:var(--aa18a430)}.atable #header-index{width:var(--aa18a430);max-width:var(--aa18a430)}.list-index{color:var(--header-text-color);font-weight:700;padding-left:var(--atable-row-padding);padding-right:1em;text-align:center;-webkit-user-select:none;user-select:none;width:var(--0fa106da);max-width:var(--0fa106da)}.atable #header-index{width:var(--0fa106da);max-width:var(--0fa106da)}.list-index{color:var(--header-text-color);font-weight:700;padding-left:var(--atable-row-padding);padding-right:1em;text-align:center;-webkit-user-select:none;user-select:none;width:var(--59561aac);max-width:var(--59561aac)}.atable #header-index{width:var(--59561aac);max-width:var(--59561aac)}:root{--primary-color: #0098c9;--primary-text-color: #ffffff;--brand-color: #202a44;--gray-5: #f2f2f2;--gray-10: #e6e6e6;--gray-20: #cccccc;--gray-50: #808080;--gray-60: #666666;--gray-80: #333333;--brand-danger: #e63c28;--brand-success: #155724;--row-color-zebra-light: #eeeeee;--row-color-zebra-dark: #dddddd;--focus-cell-background: #ffffff;--focus-cell-outline: #000000;--cell-border-color: #ffffff;--cell-text-color: #3a3c41;--active-cell-background: #ffffff;--active-cell-outline: #e6a92d;--row-border-color: var(--gray-20);--header-border-color: #ffffff;--header-text-color: var(--gray-20);--row-number-background-color: #ffffff;--input-border-color: var(--gray-20);--input-label-color: var(--gray-60);--input-active-border-color: #000000;--input-active-label-color: #000000;--required-border: #e63c28;--font-size: 10px;--font-family: Arimo, Arial, sans-serif;--table-font-size: 16px;--atable-font-family: "Arimo", sans-serif;--atable-row-padding: 0px;--atable-row-height: 1.5em;--btn-color: white;--btn-border: #cccccc;--btn-hover: #f2f2f2;--btn-label-color: black}.aform{display:flex;flex-wrap:wrap;gap:1rem;padding:1rem;border:1px solid var(--gray-5);border-left:4px solid var(--gray-5);margin-bottom:1rem;max-width:100%}@media screen and (max-width: 400px){.aform{flex-direction:column}}.aform__form-element{border:1px solid transparent;padding:0;margin:0;position:relative;box-sizing:border-box;flex-grow:1;min-width:100px}.aform__input-field{outline:1px solid transparent;border:1px solid var(--input-border-color);font-size:1rem;padding:.5rem .25rem .25rem .5rem;margin:0;border-radius:0;box-sizing:border-box;width:100%;position:relative;color:var(--cell-text-color)}.aform__field-label{color:var(--input-label-color);display:inline-block;position:absolute;padding:0 .25rem;margin:0rem;z-index:2;font-size:.7rem;font-weight:300;letter-spacing:.05rem;width:auto;box-sizing:border-box;background:#fff;margin:0;border:1px solid var(--input-border-color);grid-row:1;top:0;left:10px;border:none;transform:translateY(-50%)}p.error{display:block;display:inline-block;display:none;padding:0rem 0rem 0rem .5rem;margin:.5rem 0 .25rem 0rem;border:1px solid transparent;width:100%;width:auto;color:var(--brand-danger);font-size:.8rem;position:absolute;right:0;top:0;background:#fff;padding:.25rem;transform:translate(-1rem,-50%);margin:0}.aform__input-field:focus{border:1px solid var(--input-active-border-color)}.aform__input-field:focus+.aform__field-label{color:var(--input-active-label-color)}.aform__checkbox{cursor:pointer;width:auto;margin-top:0;display:block}.aform__checkbox:checked{accent-color:var(--primary-color);border:1px solid black}.aform__checkbox-container{width:100%;display:inline-block;text-align:left}.aform__checkbox-container input{width:auto}.aform__checkbox-container:hover+.aform__field-label{color:var(--input-active-label-color)}.aform-primary-action{font-size:100%;text-align:center;min-height:2em;padding:.25rem 1rem;border:1px solid var(--primary-color);color:var(--primary-text-color);background-color:var(--primary-color);outline:2px solid var(--primary-text-color);transition:outline-offset .2s ease;font-size:var(--font-size);margin:.5ch}.aform-primary-action:hover,.aform-primary-action:active{outline:2px solid var(--primary-text-color);outline-offset:-4px;transition:outline-offset .2s ease}tr:focus{background-color:#add8e6;outline:auto}.aform__form-btn{padding:.5rem 2rem;width:auto;border:1px solid var(--input-border-color);color:var(--input-label-color);cursor:pointer;background-color:#fff}.aform__form-btn:disabled{background-color:var(--gray-5)}.aform__file-attach{padding:1rem;display:flex;flex-wrap:wrap;gap:1rem;flex-direction:row;justify-content:center;align-items:center;border:1px dashed var(--input-border-color);width:100%}@media screen and (max-width: 400px){.aform__file-attach>.aform__form-btn{width:100%}}.aform__file-attach-feedback{color:var(--input-label-color);width:100%;padding:.5rem;text-align:center;align-self:center}.aform__file-attach-feedback>li{list-style:none;font-style:italic}.aform__file-attach-feedback>p{margin-top:0}.atable{font-family:var(--atable-font-family);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:var(--table-font-size);border-collapse:collapse}.row-index{color:var(--header-text-color);font-weight:700;text-align:center;-webkit-user-select:none;user-select:none;width:2ch}.expandable-row{border-top:1px solid var(--row-border-color);height:var(--atable-row-height);border-left:4px solid var(--row-border-color)}.expanded-row{border-bottom:1px solid var(--row-border-color);border-top:1px solid var(--row-border-color)}.expanded-row-content{border-bottom:1px solid var(--row-border-color);border-top:1px solid var(--row-border-color);padding:1.5rem}.atable__cell{border-radius:0;box-sizing:border-box;margin:0;outline:none;box-shadow:none;color:var(--cell-text-color);text-overflow:ellipsis;overflow:hidden;padding-left:.5ch!important;padding-right:.5ch;padding-top:var(--atable-row-padding);padding-bottom:var(--atable-row-padding);border-spacing:0px;border-collapse:collapse}.atable__cell:focus,.atable__cell:focus-within{background-color:var(--focus-cell-background);outline-width:2px;outline-style:solid;outline-color:var(--focus-cell-outline);box-shadow:none;min-height:1.15em;max-height:1.15em;overflow:hidden}.table-row{border-top:1px solid var(--row-border-color);height:var(--atable-row-height)}.list-index{color:var(--header-text-color);font-weight:700;padding-left:var(--atable-row-padding);padding-right:1em;text-align:center;-webkit-user-select:none;user-select:none;width:var(--2c1c9089);max-width:var(--2c1c9089)}.tree-index{color:var(--header-text-color);font-weight:700;text-align:center;-webkit-user-select:none;user-select:none;width:2ch}.atable #header-index{width:var(--2c1c9089);max-width:var(--2c1c9089)}.atable th{border-width:0px;border-style:solid;border-radius:0;padding-left:.5ch;padding-right:.5ch;padding-top:var(--atable-row-padding);padding-bottom:var(--atable-row-padding);color:var(--gray-60);height:var(--atable-row-height);font-weight:300;letter-spacing:.05rem}.atable th:focus{outline:none}.amodal{z-index:100;position:absolute;background-color:var(--row-color-zebra-dark)}.login-container{width:100%;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;font-family:var(--font-family)}.account-container{width:100%;margin-left:auto;margin-top:.5rem;margin-right:auto;display:flex;flex-direction:column;justify-content:center}.account-header{display:flex;flex-direction:column;text-align:center;margin-top:.5rem}#account-title{font-size:1.5rem;line-height:2rem;font-weight:600;letter-spacing:-.025em;margin:0}#account-subtitle{font-size:.875rem;line-height:1.25rem;margin:1rem}.login-form-container{display:grid;gap:.5rem}.login-form-element{display:grid;margin:.5rem 0;position:relative}.login-field{padding:.5rem .25rem .25rem .5rem;outline:1px solid transparent;border:1px solid var(--input-border-color);border-radius:.25rem}.login-field:focus{border:1px solid black}.btn{background-color:var(--btn-color);color:var(--btn-label-color);border:1px solid var(--btn-border);margin:.5rem 0;padding:.25rem;position:relative;cursor:pointer}.btn:hover{background-color:var(--btn-hover)}.btn:disabled{background-color:light-dark(rgba(239,239,239,.3),rgba(59,59,59,.3));color:light-dark(rgb(84,84,84),rgb(170,170,170))}.disabled{opacity:.5}.loading-icon{animation:spin 1s linear infinite forwards;display:inline-block;margin-right:.2rem;line-height:0;font-size:1rem;position:relative;top:.2rem}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}
1
+ @import"https://fonts.googleapis.com/css2?family=Arimo:ital,wght@0,400..700;1,400..700&display=swap";:root{--primary-color: #0098c9;--primary-text-color: #ffffff;--brand-color: #202a44;--gray-5: #f2f2f2;--gray-10: #e6e6e6;--gray-20: #cccccc;--gray-50: #808080;--gray-60: #666666;--gray-80: #333333;--brand-danger: #e63c28;--brand-success: #155724;--row-color-zebra-light: #eeeeee;--row-color-zebra-dark: #dddddd;--focus-cell-background: #ffffff;--focus-cell-outline: #000000;--cell-border-color: #ffffff;--cell-text-color: #3a3c41;--active-cell-background: #ffffff;--active-cell-outline: #e6a92d;--row-border-color: var(--gray-20);--header-border-color: #ffffff;--header-text-color: var(--gray-20);--row-number-background-color: #ffffff;--input-border-color: var(--gray-20);--input-label-color: var(--gray-60);--input-active-border-color: #000000;--input-active-label-color: #000000;--required-border: #e63c28;--font-size: 10px;--font-family: Arimo, Arial, sans-serif;--table-font-size: 16px;--atable-font-family: "Arimo", sans-serif;--atable-row-padding: 0px;--atable-row-height: 1.5em;--btn-color: white;--btn-border: #cccccc;--btn-hover: #f2f2f2;--btn-label-color: black}.aform{display:flex;flex-wrap:wrap;gap:1rem;padding:1rem;border:1px solid var(--gray-5);border-left:4px solid var(--gray-5);margin-bottom:1rem;max-width:100%}@media screen and (max-width: 400px){.aform{flex-direction:column}}.aform__form-element{border:1px solid transparent;padding:0;margin:0;position:relative;box-sizing:border-box;flex-grow:1;min-width:100px}.aform__input-field{outline:1px solid transparent;border:1px solid var(--input-border-color);font-size:1rem;padding:.5rem .25rem .25rem .5rem;margin:0;border-radius:0;box-sizing:border-box;width:100%;position:relative;color:var(--cell-text-color)}.aform__field-label{color:var(--input-label-color);display:inline-block;position:absolute;padding:0 .25rem;margin:0rem;z-index:2;font-size:.7rem;font-weight:300;letter-spacing:.05rem;width:auto;box-sizing:border-box;background:#fff;margin:0;border:1px solid var(--input-border-color);grid-row:1;top:0;left:10px;border:none;transform:translateY(-50%)}p.error{display:block;display:inline-block;display:none;padding:0rem 0rem 0rem .5rem;margin:.5rem 0 .25rem 0rem;border:1px solid transparent;width:100%;width:auto;color:var(--brand-danger);font-size:.8rem;position:absolute;right:0;top:0;background:#fff;padding:.25rem;transform:translate(-1rem,-50%);margin:0}.aform__input-field:focus{border:1px solid var(--input-active-border-color)}.aform__input-field:focus+.aform__field-label{color:var(--input-active-label-color)}.aform__checkbox{cursor:pointer;width:auto;margin-top:0;display:block}.aform__checkbox:checked{accent-color:var(--primary-color);border:1px solid black}.aform__checkbox-container{width:100%;display:inline-block;text-align:left}.aform__checkbox-container input{width:auto}.aform__checkbox-container:hover+.aform__field-label{color:var(--input-active-label-color)}.aform-primary-action{font-size:100%;text-align:center;min-height:2em;padding:.25rem 1rem;border:1px solid var(--primary-color);color:var(--primary-text-color);background-color:var(--primary-color);outline:2px solid var(--primary-text-color);transition:outline-offset .2s ease;font-size:var(--font-size);margin:.5ch}.aform-primary-action:hover,.aform-primary-action:active{outline:2px solid var(--primary-text-color);outline-offset:-4px;transition:outline-offset .2s ease}tr:focus{background-color:#add8e6;outline:auto}.aform__form-btn{padding:.5rem 2rem;width:auto;border:1px solid var(--input-border-color);color:var(--input-label-color);cursor:pointer;background-color:#fff}.aform__form-btn:disabled{background-color:var(--gray-5)}.aform__file-attach{padding:1rem;display:flex;flex-wrap:wrap;gap:1rem;flex-direction:row;justify-content:center;align-items:center;border:1px dashed var(--input-border-color);width:100%}@media screen and (max-width: 400px){.aform__file-attach>.aform__form-btn{width:100%}}.aform__file-attach-feedback{color:var(--input-label-color);width:100%;padding:.5rem;text-align:center;align-self:center}.aform__file-attach-feedback>li{list-style:none;font-style:italic}.aform__file-attach-feedback>p{margin-top:0}.atable{font-family:var(--atable-font-family);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:var(--table-font-size);border-collapse:collapse}.row-index{color:var(--header-text-color);font-weight:700;text-align:center;-webkit-user-select:none;user-select:none;width:2ch}.expandable-row{border-top:1px solid var(--row-border-color);height:var(--atable-row-height);border-left:4px solid var(--row-border-color)}.expanded-row{border-bottom:1px solid var(--row-border-color);border-top:1px solid var(--row-border-color)}.expanded-row-content{border-bottom:1px solid var(--row-border-color);border-top:1px solid var(--row-border-color);padding:1.5rem}.atable__cell{border-radius:0;box-sizing:border-box;margin:0;outline:none;box-shadow:none;color:var(--cell-text-color);padding-left:.5ch!important;padding-right:.5ch;padding-top:var(--atable-row-padding);padding-bottom:var(--atable-row-padding);border-spacing:0px;border-collapse:collapse;overflow:hidden;text-overflow:ellipsis;order:1}.atable__cell span{overflow:hidden;text-overflow:ellipsis}.atable__cell:focus,.atable__cell:focus-within{background-color:var(--focus-cell-background);outline-width:2px;outline-style:solid;outline-offset:-1px;outline-color:var(--focus-cell-outline);box-shadow:none;min-height:1.15em;max-height:1.15em;overflow:hidden;box-sizing:border-box}.table-row{border-top:1px solid var(--row-border-color);height:var(--atable-row-height);display:flex;background-color:#fff}.list-index{color:var(--header-text-color);font-weight:700;padding-left:var(--atable-row-padding);padding-right:1em;text-align:center;-webkit-user-select:none;user-select:none;width:30px;text-overflow:ellipsis;overflow:hidden}.tree-index{color:var(--header-text-color);font-weight:700;text-align:center;-webkit-user-select:none;user-select:none;width:2ch}.atable #header-index{width:30px;padding-right:1em;padding-left:0;box-sizing:border-box}.atable-header-row{display:flex}.atable th{border-width:0px;border-style:solid;border-radius:0;padding-left:.5ch;padding-right:.5ch;padding-top:var(--atable-row-padding);padding-bottom:var(--atable-row-padding);color:var(--gray-60);height:var(--atable-row-height);font-weight:300;letter-spacing:.05rem;order:1;box-sizing:border-box}#header-index{box-sizing:content-box}.atable th:focus{outline:none}.amodal{z-index:100;position:absolute;background-color:var(--row-color-zebra-dark)}.sticky-index{position:sticky;left:0;z-index:1;order:0}.sticky-column,th.sticky-column,td.sticky-column,th.sticky-index,td.sticky-index{position:sticky;z-index:1;order:0;background:#fff}.sticky-column-edge,.atable th.sticky-column-edge{border-right:1px solid var(--row-border-color);border-right-width:1px}.login-container{width:100%;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;font-family:var(--font-family)}.account-container{width:100%;margin-left:auto;margin-top:.5rem;margin-right:auto;display:flex;flex-direction:column;justify-content:center}.account-header{display:flex;flex-direction:column;text-align:center;margin-top:.5rem}#account-title{font-size:1.5rem;line-height:2rem;font-weight:600;letter-spacing:-.025em;margin:0}#account-subtitle{font-size:.875rem;line-height:1.25rem;margin:1rem}.login-form-container{display:grid;gap:.5rem}.login-form-element{display:grid;margin:.5rem 0;position:relative}.login-field{padding:.5rem .25rem .25rem .5rem;outline:1px solid transparent;border:1px solid var(--input-border-color);border-radius:.25rem}.login-field:focus{border:1px solid black}.btn{background-color:var(--btn-color);color:var(--btn-label-color);border:1px solid var(--btn-border);margin:.5rem 0;padding:.25rem;position:relative;cursor:pointer}.btn:hover{background-color:var(--btn-hover)}.btn:disabled{background-color:light-dark(rgba(239,239,239,.3),rgba(59,59,59,.3));color:light-dark(rgb(84,84,84),rgb(170,170,170))}.disabled{opacity:.5}.loading-icon{animation:spin 1s linear infinite forwards;display:inline-block;margin-right:.2rem;line-height:0;font-size:1rem;position:relative;top:.2rem}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonecrop/atable",
3
- "version": "0.2.38",
3
+ "version": "0.2.40",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "author": {
@@ -35,8 +35,8 @@
35
35
  "@vueuse/core": "^11.1.0",
36
36
  "uuid": "^10.0.0",
37
37
  "vue": "^3.5.6",
38
- "@stonecrop/themes": "0.2.38",
39
- "@stonecrop/utilities": "0.2.38"
38
+ "@stonecrop/utilities": "0.2.40",
39
+ "@stonecrop/themes": "0.2.40"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@microsoft/api-documenter": "^7.25.3",
@@ -3,8 +3,8 @@
3
3
  ref="cell"
4
4
  :data-colindex="colIndex"
5
5
  :data-rowindex="rowIndex"
6
- :data-editable="tableData.columns[colIndex].edit"
7
- :contenteditable="tableData.columns[colIndex].edit"
6
+ :data-editable="column.edit"
7
+ :contenteditable="column.edit"
8
8
  :tabindex="tabIndex"
9
9
  :spellcheck="false"
10
10
  :style="cellStyle"
@@ -14,12 +14,13 @@
14
14
  @input="onChange"
15
15
  @click="handleInput"
16
16
  @mousedown="handleInput"
17
- class="atable__cell">
17
+ class="atable__cell"
18
+ :class="pinned ? 'sticky-column' : ''">
18
19
  <component
19
- v-if="tableData.columns[colIndex].cellComponent"
20
- :is="tableData.columns[colIndex].cellComponent"
20
+ v-if="column.cellComponent"
21
+ :is="column.cellComponent"
21
22
  :value="displayValue"
22
- v-bind="tableData.columns[colIndex].cellComponentProps">
23
+ v-bind="column.cellComponentProps">
23
24
  </component>
24
25
  <span v-else>{{ displayValue }}</span>
25
26
  </td>
@@ -30,7 +31,7 @@ import { KeypressHandlers, defaultKeypressHandlers, useKeyboardNav } from '@ston
30
31
  import { computed, CSSProperties, inject, ref, useTemplateRef } from 'vue'
31
32
 
32
33
  import TableDataStore from '.'
33
- import type { CellFormatContext } from '@/types'
34
+ import type { CellContext } from '@/types'
34
35
 
35
36
  const {
36
37
  colIndex,
@@ -44,6 +45,7 @@ const {
44
45
  tableid: string
45
46
  addNavigation?: boolean | KeypressHandlers
46
47
  tabIndex?: number
48
+ pinned?: boolean
47
49
  }>()
48
50
 
49
51
  const tableData = inject<TableDataStore>(tableid)
@@ -51,36 +53,37 @@ const cellRef = useTemplateRef<HTMLTableCellElement>('cell')
51
53
  const currentData = ref('')
52
54
  const cellModified = ref(false)
53
55
 
56
+ const table = tableData.table
57
+ const column = tableData.columns[colIndex]
58
+ const row = tableData.rows[rowIndex]
59
+
54
60
  const displayValue = computed(() => {
55
- const data = tableData.cellData<any>(colIndex, rowIndex)
56
- if (tableData.columns[colIndex].format) {
57
- const table = tableData.table
58
- const row = tableData.rows[rowIndex]
59
- const column = tableData.columns[colIndex]
60
- const format = column.format
61
-
62
- if (typeof format === 'function') {
63
- return format(data, { table, row, column })
64
- } else if (typeof format === 'string') {
65
- // parse format function from string
66
- // eslint-disable-next-line @typescript-eslint/no-implied-eval
67
- const formatFn: (args: any, context?: CellFormatContext) => string = Function(`"use strict";return (${format})`)()
68
- return formatFn(data, { table, row, column })
69
- } else {
70
- return data
71
- }
72
- } else {
73
- return data
61
+ const cellData = tableData.cellData<any>(colIndex, rowIndex)
62
+ const format = column.format
63
+
64
+ if (!format) {
65
+ return cellData
66
+ }
67
+
68
+ if (typeof format === 'function') {
69
+ return format(cellData, { table, row, column })
70
+ } else if (typeof format === 'string') {
71
+ // parse format function from string
72
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
73
+ const formatFn: (value: any, context?: CellContext) => string = Function(`"use strict";return (${format})`)()
74
+ return formatFn(cellData, { table, row, column })
74
75
  }
76
+
77
+ return cellData
75
78
  })
76
79
 
77
80
  const handleInput = () => {
78
- if (tableData.columns[colIndex].mask) {
81
+ if (column.mask) {
79
82
  // TODO: add masking to cell values
80
- // tableData.columns[colIndex].mask(event)
83
+ // column.mask(event)
81
84
  }
82
85
 
83
- if (tableData.columns[colIndex].modalComponent) {
86
+ if (column.modalComponent) {
84
87
  const domRect = cellRef.value.getBoundingClientRect()
85
88
  tableData.modal.visible = true
86
89
  tableData.modal.colIndex = colIndex
@@ -89,8 +92,14 @@ const handleInput = () => {
89
92
  tableData.modal.top = domRect.top + domRect.height
90
93
  tableData.modal.left = domRect.left
91
94
  tableData.modal.width = cellWidth.value
92
- tableData.modal.component = tableData.columns[colIndex].modalComponent
93
- tableData.modal.componentProps = tableData.columns[colIndex].modalComponentProps
95
+
96
+ if (typeof column.modalComponent === 'function') {
97
+ tableData.modal.component = column.modalComponent({ table, row, column })
98
+ } else {
99
+ tableData.modal.component = column.modalComponent
100
+ }
101
+
102
+ tableData.modal.componentProps = column.modalComponentExtraProps
94
103
  }
95
104
  }
96
105
 
@@ -124,7 +133,7 @@ if (addNavigation) {
124
133
  // const updateData = (event: Event) => {
125
134
  // if (event) {
126
135
  // // custom components need to handle their own updateData, this is the default
127
- // if (!tableData.columns[colIndex].component) {
136
+ // if (!column.component) {
128
137
  // tableData.setCellData(rowIndex, colIndex, cell.value.innerHTML)
129
138
  // }
130
139
  // cellModified.value = true
@@ -132,11 +141,11 @@ if (addNavigation) {
132
141
  // }
133
142
 
134
143
  const textAlign = computed(() => {
135
- return tableData.columns[colIndex].align || 'center'
144
+ return column.align || 'center'
136
145
  })
137
146
 
138
147
  const cellWidth = computed(() => {
139
- return tableData.columns[colIndex].width || '40ch'
148
+ return column.width || '40ch'
140
149
  })
141
150
 
142
151
  const onFocus = () => {
@@ -151,7 +160,7 @@ const onChange = () => {
151
160
  currentData.value = cellRef.value.textContent
152
161
  cellRef.value.dispatchEvent(new Event('change'))
153
162
  cellModified.value = true // set display instead
154
- if (!tableData.columns[colIndex].format) {
163
+ if (!column.format) {
155
164
  // TODO: need to setup reverse format function
156
165
  tableData.setCellData(rowIndex, colIndex, currentData.value)
157
166
  }
@@ -17,16 +17,13 @@ import { type KeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'
17
17
  import { computed, inject, useTemplateRef } from 'vue'
18
18
 
19
19
  import TableDataStore from '.'
20
- import type { TableRow } from '@/types'
21
20
 
22
21
  const {
23
- row,
24
22
  rowIndex,
25
23
  tableid,
26
24
  tabIndex = -1,
27
25
  addNavigation,
28
26
  } = defineProps<{
29
- row: TableRow
30
27
  rowIndex: number
31
28
  tableid: string
32
29
  tabIndex?: number
@@ -2,13 +2,18 @@
2
2
  <tr ref="rowEl" :tabindex="tabIndex" v-show="isRowVisible" class="table-row">
3
3
  <!-- render numbered/tree view index -->
4
4
  <slot name="index">
5
- <td v-if="tableData.config.view === 'list'" :tabIndex="-1" class="list-index">
5
+ <td
6
+ v-if="tableData.config.view === 'list'"
7
+ :tabIndex="-1"
8
+ class="list-index"
9
+ :class="hasPinnedColumns ? 'sticky-index' : ''">
6
10
  {{ rowIndex + 1 }}
7
11
  </td>
8
12
  <td
9
13
  v-else-if="tableData.config.view === 'tree'"
10
14
  :tabIndex="-1"
11
15
  class="tree-index"
16
+ :class="hasPinnedColumns ? 'sticky-index' : ''"
12
17
  @click="toggleRowExpand(rowIndex)">
13
18
  {{ rowExpandSymbol }}
14
19
  </td>
@@ -24,16 +29,13 @@ import { type KeypressHandlers, useKeyboardNav, defaultKeypressHandlers } from '
24
29
  import { computed, inject, useTemplateRef } from 'vue'
25
30
 
26
31
  import TableDataStore from '.'
27
- import type { TableRow } from '@/types'
28
32
 
29
33
  const {
30
- row,
31
34
  rowIndex,
32
35
  tableid,
33
36
  tabIndex = -1,
34
37
  addNavigation = false, // default to allowing cell navigation
35
38
  } = defineProps<{
36
- row: TableRow
37
39
  rowIndex: number
38
40
  tableid: string
39
41
  tabIndex?: number
@@ -43,6 +45,8 @@ const {
43
45
  const tableData = inject<TableDataStore>(tableid)
44
46
  const rowRef = useTemplateRef<HTMLTableRowElement>('rowEl')
45
47
 
48
+ const hasPinnedColumns = computed(() => tableData.columns.some(col => col.pinned))
49
+
46
50
  const isRowVisible = computed(() => {
47
51
  return tableData.config.view !== 'tree' || tableData.display[rowIndex].isRoot || tableData.display[rowIndex].open
48
52
  })
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <table
3
+ ref="table"
3
4
  class="atable"
4
5
  :style="{ width: tableData.config.fullWidth ? '100%' : 'auto' }"
5
6
  v-on-click-outside="closeModal">
@@ -21,6 +22,7 @@
21
22
  :tableid="tableData.id"
22
23
  :col="col"
23
24
  spellcheck="false"
25
+ :pinned="col.pinned"
24
26
  :rowIndex="rowIndex"
25
27
  :colIndex="colIndex + (tableData.zeroColumn ? 0 : -1)"
26
28
  :component="col.cellComponent"
@@ -61,7 +63,7 @@
61
63
 
62
64
  <script setup lang="ts">
63
65
  import { vOnClickOutside } from '@vueuse/components'
64
- import { nextTick, provide, watch } from 'vue'
66
+ import { nextTick, provide, watch, onMounted, useTemplateRef } from 'vue'
65
67
 
66
68
  import TableDataStore from '.'
67
69
  import ACell from '@/components/ACell.vue'
@@ -76,18 +78,17 @@ const {
76
78
  columns,
77
79
  rows = [],
78
80
  config = new Object(),
79
- tableid,
80
81
  } = defineProps<{
81
82
  id?: string
82
83
  modelValue: TableRow[]
83
84
  columns: TableColumn[]
84
85
  rows?: TableRow[]
85
86
  config?: TableConfig
86
- tableid?: string
87
87
  }>()
88
88
 
89
89
  const emit = defineEmits(['update:modelValue'])
90
90
 
91
+ const tableRef = useTemplateRef<HTMLTableElement>('table')
91
92
  const rowsValue = modelValue ? modelValue : rows
92
93
  const tableData = new TableDataStore(id, columns, rowsValue, config)
93
94
  provide(tableData.id, tableData)
@@ -100,6 +101,46 @@ watch(
100
101
  { deep: true }
101
102
  )
102
103
 
104
+ onMounted(() => {
105
+ assignStickyCellWidths()
106
+
107
+ // in tree view, a mutation observer is needed to capture and adjust expanded rows
108
+ if (tableData.config.view === 'tree') {
109
+ const observer = new MutationObserver(() => assignStickyCellWidths())
110
+ observer.observe(tableRef.value, { childList: true, subtree: true })
111
+ }
112
+ })
113
+
114
+ const assignStickyCellWidths = () => {
115
+ const table = tableRef.value
116
+
117
+ // set header cell width to match sticky cells' width
118
+ const headerCells = Array.from(table.rows[0].cells)
119
+ for (const [index, headerCell] of headerCells.entries()) {
120
+ const rowCell = table.rows[1].cells[index]
121
+ headerCell.style.width = `${rowCell.offsetWidth}px`
122
+ }
123
+
124
+ // pin cells in row that are sticky
125
+ for (const row of table.rows) {
126
+ let totalWidth = 0
127
+ const columns: HTMLTableCellElement[] = []
128
+
129
+ for (const column of row.cells) {
130
+ if (column.classList.contains('sticky-column') || column.classList.contains('sticky-index')) {
131
+ column.style.left = `${totalWidth}px`
132
+ totalWidth += column.offsetWidth
133
+ columns.push(column)
134
+ }
135
+ }
136
+
137
+ if (columns.length > 0) {
138
+ const lastColumn = columns[columns.length - 1]
139
+ lastColumn.classList.add('sticky-column-edge')
140
+ }
141
+ }
142
+ }
143
+
103
144
  // const formatCell = (event?: KeyboardEvent, column?: TableColumn, cellData?: any) => {
104
145
  // let colIndex: number
105
146
  // const target = event?.target as HTMLTableCellElement
@@ -1,8 +1,13 @@
1
1
  <template>
2
2
  <thead id="resizable" v-if="columns.length">
3
3
  <tr class="atable-header-row" tabindex="-1">
4
- <th v-if="tableData.zeroColumn" id="header-index" />
5
- <th v-for="(column, colKey) in columns" :key="column.name" tabindex="-1" :style="getHeaderCellStyle(column)">
4
+ <th v-if="tableData.zeroColumn" id="header-index" :class="hasPinnedColumns ? 'sticky-index' : ''" />
5
+ <th
6
+ v-for="(column, colKey) in columns"
7
+ :key="column.name"
8
+ tabindex="-1"
9
+ :style="getHeaderCellStyle(column)"
10
+ :class="column.pinned ? 'sticky-column' : ''">
6
11
  <slot>{{ column.label || String.fromCharCode(colKey + 97).toUpperCase() }}</slot>
7
12
  </th>
8
13
  </tr>
@@ -10,7 +15,7 @@
10
15
  </template>
11
16
 
12
17
  <script setup lang="ts">
13
- import { CSSProperties, inject } from 'vue'
18
+ import { CSSProperties, inject, computed } from 'vue'
14
19
 
15
20
  import TableDataStore from '.'
16
21
  import type { TableColumn } from '@/types'
@@ -19,6 +24,8 @@ const { columns, tableid } = defineProps<{ columns: TableColumn[]; tableid?: str
19
24
 
20
25
  const tableData = inject<TableDataStore>(tableid)
21
26
 
27
+ const hasPinnedColumns = computed(() => tableData.columns.some(col => col.pinned))
28
+
22
29
  const getHeaderCellStyle = (column: TableColumn): CSSProperties => ({
23
30
  minWidth: column.width || '40ch',
24
31
  textAlign: column.align || 'center',
package/src/index.ts CHANGED
@@ -7,7 +7,7 @@ import ATable from '@/components/ATable.vue'
7
7
  import ATableHeader from '@/components/ATableHeader.vue'
8
8
  import ATableModal from '@/components/ATableModal.vue'
9
9
  import TableDataStore from './components'
10
- export type { CellFormatContext, TableColumn, TableConfig, TableDisplay, TableRow, TableModal } from '@/types'
10
+ export type { CellContext, TableColumn, TableConfig, TableDisplay, TableRow, TableModal } from '@/types'
11
11
 
12
12
  /**
13
13
  * Install all ATable components
@@ -8,17 +8,18 @@ export type TableColumn = {
8
8
  label?: string
9
9
  type?: string
10
10
  width?: string
11
+ pinned?: boolean
11
12
 
12
13
  cellComponent?: string
13
14
  cellComponentProps?: Record<string, any>
14
- modalComponent?: string
15
- modalComponentProps?: Record<string, any>
15
+ modalComponent?: string | ((context?: CellContext) => string)
16
+ modalComponentExtraProps?: Record<string, any>
16
17
 
17
- format?: string | ((value: any, context?: CellFormatContext) => string)
18
+ format?: string | ((value: any, context?: CellContext) => string)
18
19
  mask?: (value: any) => any
19
20
  }
20
21
 
21
- export type CellFormatContext = {
22
+ export type CellContext = {
22
23
  row: TableRow
23
24
  column: TableColumn
24
25
  table: TableDataStore['table']