gridjs-spreadsheet 26.8.0 → 26.8.1

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.
@@ -1194,4 +1194,29 @@
1194
1194
  <rect x="24" y="17" width="6" height="20" fill="#FFFFFF" id="redact-plus-v" />
1195
1195
  </g>
1196
1196
  </g>
1197
- &#10; </svg>
1197
+ &#10;
1198
+ <g id="RedactionSearchResult" transform="matrix(0.3033,0,0,0.3033,180,126)">
1199
+
1200
+
1201
+
1202
+ <!-- Unified blue-grey rounded background to indicate 'search' context -->
1203
+ <rect x="4" y="4" width="54" height="54" fill="#56754B" rx="4" ry="4" id="bg-rect" />
1204
+ <!-- Search results list: two white horizontal lines representing the searched content -->
1205
+ <rect x="10" y="10" width="14" height="3" fill="#FFFFFF" rx="1.5" id="search-line-1" />
1206
+ <rect x="10" y="16" width="14" height="3" fill="#FFFFFF" rx="1.5" id="search-line-2" />
1207
+
1208
+ <!-- Magnifying glass: represents the 'search' action, positioned on the right side of the list -->
1209
+ <circle cx="35" cy="18" r="7" fill="none" stroke="#FFFFFF" stroke-width="2.5" id="search-glass" />
1210
+ <line x1="42" y1="23" x2="47" y2="28" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" id="search-handle" />
1211
+
1212
+ <g transform="translate(27, 27) scale(0.66) translate(-32, -16)">
1213
+ <rect x="9" y="9" width="36" height="36" fill="#E53935" rx="4" ry="4" id="redact-rect" />
1214
+ <line x1="9" y1="9" x2="45" y2="45" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" id="redact-line" />
1215
+ <rect x="17" y="24" width="20" height="6" fill="#FFFFFF" id="redact-plus-h" />
1216
+ <rect x="24" y="17" width="6" height="20" fill="#FFFFFF" id="redact-plus-v" />
1217
+ </g>
1218
+
1219
+
1220
+ </g> &#10;
1221
+
1222
+ </svg>
package/angular.d.ts CHANGED
@@ -8,7 +8,7 @@ import type {
8
8
  SimpleChanges,
9
9
  } from '@angular/core';
10
10
  import type * as i0 from '@angular/core';
11
- import type Spreadsheet from 'gridjs-spreadsheet';
11
+ import type Spreadsheet, { SemanticAutomationOptions } from 'gridjs-spreadsheet';
12
12
  import type { GridJsAdapter } from './shared';
13
13
 
14
14
  export declare class GridJsSpreadsheetComponent implements AfterViewInit, OnChanges, OnDestroy {
@@ -21,6 +21,7 @@ export declare class GridJsSpreadsheetComponent implements AfterViewInit, OnChan
21
21
  height: string;
22
22
  showToolbar: boolean;
23
23
  showContextmenu: boolean;
24
+ semanticAutomation: SemanticAutomationOptions | null;
24
25
  ready: EventEmitter<{ instance: Spreadsheet; adapter: GridJsAdapter }>;
25
26
  change: EventEmitter<any[]>;
26
27
  error: EventEmitter<any>;
@@ -47,6 +48,7 @@ export declare class GridJsSpreadsheetComponent implements AfterViewInit, OnChan
47
48
  height: { alias: 'height'; required: false };
48
49
  showToolbar: { alias: 'showToolbar'; required: false };
49
50
  showContextmenu: { alias: 'showContextmenu'; required: false };
51
+ semanticAutomation: { alias: 'semanticAutomation'; required: false };
50
52
  },
51
53
  {
52
54
  ready: 'ready';
package/angular.js CHANGED
@@ -29,6 +29,7 @@ export class GridJsSpreadsheetComponent {
29
29
  height = 'calc(100vh - 96px)';
30
30
  showToolbar = true;
31
31
  showContextmenu = true;
32
+ semanticAutomation = null;
32
33
 
33
34
  ready = new EventEmitter();
34
35
  change = new EventEmitter();
@@ -80,6 +81,7 @@ export class GridJsSpreadsheetComponent {
80
81
  this.locale,
81
82
  String(this.showToolbar),
82
83
  String(this.showContextmenu),
84
+ JSON.stringify(this.semanticAutomation || null),
83
85
  ].join('|');
84
86
 
85
87
  if (mountKey === this.lastMountKey && this.adapter) return;
@@ -100,6 +102,7 @@ export class GridJsSpreadsheetComponent {
100
102
  token: this.token,
101
103
  showToolbar: this.showToolbar,
102
104
  showContextmenu: this.showContextmenu,
105
+ semanticAutomation: this.semanticAutomation,
103
106
  callbacks: {
104
107
  ready: (instance, activeAdapter) => this.zone.run(() => this.ready.emit({ instance, adapter: activeAdapter })),
105
108
  change: (...args) => this.zone.run(() => this.change.emit(args)),
@@ -154,6 +157,7 @@ GridJsSpreadsheetComponent.ɵcmp = /* @__PURE__ */ i0.ɵɵngDeclareComponent({
154
157
  height: 'height',
155
158
  showToolbar: 'showToolbar',
156
159
  showContextmenu: 'showContextmenu',
160
+ semanticAutomation: 'semanticAutomation',
157
161
  },
158
162
  outputs: {
159
163
  ready: 'ready',
package/index.d.ts CHANGED
@@ -69,6 +69,123 @@ declare module 'gridjs-spreadsheet' {
69
69
  * @returns Promise<string> for the new reason, or null to cancel
70
70
  */
71
71
  onRedactionAddReason?: (existingReasons: string[]) => Promise<string | null>;
72
+ /** Versioned Object API for AI Agent and automated tests. Disabled by default. */
73
+ semanticAutomation?: SemanticAutomationOptions;
74
+ }
75
+
76
+ export interface SemanticAutomationOptions {
77
+ enabled?: boolean;
78
+ instanceId?: string;
79
+ }
80
+
81
+ export type SemanticRuntimePhase =
82
+ | 'disabled'
83
+ | 'initializing'
84
+ | 'loading'
85
+ | 'rendering'
86
+ | 'ready'
87
+ | 'updating'
88
+ | 'failed'
89
+ | 'destroyed';
90
+
91
+ export interface SemanticRuntimeState {
92
+ contractVersion: string;
93
+ instanceId: string;
94
+ instanceGeneration: string;
95
+ workbookSessionId: string | null;
96
+ phase: SemanticRuntimePhase;
97
+ revision: number;
98
+ failure: { code: string; message: string; retryable: boolean } | null;
99
+ activeOperationIds: string[];
100
+ lastOperationId: string | null;
101
+ activeSheetId: string | null;
102
+ }
103
+
104
+ export interface SemanticOperation {
105
+ operationId: string;
106
+ kind: string;
107
+ action: string;
108
+ instanceGeneration: string;
109
+ workbookSessionId: string | null;
110
+ parentOperationId: string | null;
111
+ phase: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
112
+ progress: number;
113
+ revision: number | null;
114
+ result: Record<string, any> | null;
115
+ error: { code: string; message: string; retryable: boolean } | null;
116
+ }
117
+
118
+ export interface SemanticStateRequest {
119
+ kind: 'workbook' | 'sheets' | 'sheet' | 'cell' | 'range' | 'selection';
120
+ sheetId?: string;
121
+ address?: string;
122
+ range?: string;
123
+ offset?: number;
124
+ limit?: number;
125
+ }
126
+
127
+ export interface SemanticStateSnapshot {
128
+ contractVersion: string;
129
+ instanceId: string;
130
+ instanceGeneration: string;
131
+ workbookSessionId: string;
132
+ revision: number;
133
+ target: Record<string, any>;
134
+ state: Record<string, any>;
135
+ }
136
+
137
+ export type SemanticCellValue =
138
+ | { kind: 'blank' }
139
+ | { kind: 'text'; value: string }
140
+ | { kind: 'number'; value: number }
141
+ | { kind: 'boolean'; value: boolean };
142
+
143
+ export type SemanticEditableCellValue =
144
+ | { kind: 'blank' }
145
+ | { kind: 'text'; value: string };
146
+
147
+ export type SemanticActionRequest =
148
+ | { action: 'sheet.activate'; parameters: { sheetId: string }; invocationId?: string }
149
+ | { action: 'cell.activate'; parameters: { sheetId: string; address: string }; invocationId?: string }
150
+ | { action: 'range.select'; parameters: { sheetId: string; address?: string; range?: string }; invocationId?: string }
151
+ | { action: 'cell.setValue'; parameters: { sheetId: string; address: string; value: SemanticEditableCellValue }; invocationId?: string };
152
+
153
+ export interface SemanticActionReceipt {
154
+ operationId: string;
155
+ action: string;
156
+ instanceGeneration: string;
157
+ workbookSessionId: string;
158
+ phase: 'running';
159
+ }
160
+
161
+ export interface SemanticFacade {
162
+ describeContract(): Record<string, any>;
163
+ getCapabilities(): Record<string, any>;
164
+ getContract(): Record<string, any>;
165
+ getRuntimeState(): SemanticRuntimeState;
166
+ waitForRuntime(options?: { phase?: SemanticRuntimePhase; timeoutMs?: number; signal?: AbortSignal }): Promise<SemanticRuntimeState>;
167
+ subscribe(options: { event?: 'runtimechange' | 'operationchange' | 'sheetchange' | 'selectionchange' | 'cellchange' | '*'; fromRevision?: number; onEvent: (event: Record<string, any>) => void }): { unsubscribe(): void };
168
+ getOperation(operationId: string): SemanticOperation;
169
+ listOperations(): SemanticOperation[];
170
+ waitForOperation(options: { operationId: string; timeoutMs?: number; signal?: AbortSignal }): Promise<SemanticOperation>;
171
+ getState(request: SemanticStateRequest): SemanticStateSnapshot;
172
+ query(request: SemanticStateRequest): SemanticStateSnapshot;
173
+ getAvailableActions(request?: Pick<SemanticStateRequest, 'kind' | 'sheetId'>): ReadonlyArray<{ action: string; capability: string }>;
174
+ perform(request: SemanticActionRequest): SemanticActionReceipt;
175
+ }
176
+
177
+ export interface SemanticInstanceDescriptor {
178
+ instanceId: string;
179
+ instanceGeneration: string;
180
+ contractVersion: string;
181
+ runtimePhase: SemanticRuntimePhase;
182
+ workbookSessionId: string | null;
183
+ }
184
+
185
+ export interface GridJSSemanticAutomationRegistry {
186
+ readonly version: '1.0.0';
187
+ listInstances(): SemanticInstanceDescriptor[];
188
+ getInstance(instanceId: string): SemanticFacade | null;
72
189
  }
73
190
 
74
191
  export type CELL_SELECTED = 'cell-selected';
@@ -92,6 +209,7 @@ declare module 'gridjs-spreadsheet' {
92
209
  export type REDACTION_UPDATED = 'redaction-updated';
93
210
  export type REDACTION_REASON_INSERTED = 'redactionReason-inserted';
94
211
  export type REDACTION_TRANSPARENCY_TOGGLED = 'redactionTransparency-toggled';
212
+ export type SEARCH_REDACTED = 'search-redacted';
95
213
  export type CUSTOM_BUTTON = 'custom-button';
96
214
  export type UPDATE_SERVER_ERROR = 'updateServerError';
97
215
  export type UPDATE_CELL_ERROR = 'updateCellError';
@@ -279,6 +397,10 @@ declare module 'gridjs-spreadsheet' {
279
397
  envt: REDACTION_TRANSPARENCY_TOGGLED,
280
398
  callback: (isTransparent: boolean) => void
281
399
  ): void;
400
+ (
401
+ envt: SEARCH_REDACTED,
402
+ callback: (sheetNames: string[], detail: { keywords: string, isCaseSensitive: boolean, matchWholeCell: boolean, reason: string, color: string, baseId: string }) => void
403
+ ): void;
282
404
  (
283
405
  envt: CUSTOM_BUTTON,
284
406
  callback: (tag: string, button: CustomToolbarButton) => void
@@ -366,6 +488,8 @@ declare module 'gridjs-spreadsheet' {
366
488
  constructor(container: string | HTMLElement, opts?: Options);
367
489
  /** Build version string (injected at compile time) */
368
490
  readonly version: string;
491
+ /** Public Semantic Automation facade. */
492
+ semantic: SemanticFacade;
369
493
  on: SpreadsheetEventHandler;
370
494
  /**
371
495
  * retrieve cell
@@ -548,6 +672,7 @@ declare module 'gridjs-spreadsheet' {
548
672
  global {
549
673
  interface Window {
550
674
  x_spreadsheet(container: string | HTMLElement, opts?: Options): Spreadsheet;
675
+ GridJSSemanticAutomation?: GridJSSemanticAutomationRegistry;
551
676
  }
552
677
  }
553
678
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gridjs-spreadsheet",
3
- "version": "26.8.0",
3
+ "version": "26.8.1",
4
4
  "description": "Lightweight, high-performance JavaScript spreadsheet component for building online Excel editors and web spreadsheet apps. Supports React, Vue 3, and Angular with TypeScript declarations. Features include formulas, charts, formatting, data validation, copy/paste from Excel, and server-side integration.",
5
5
  "types": "index.d.ts",
6
6
  "main": "xspreadsheet.js",
package/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { CSSProperties } from 'react';
2
- import type Spreadsheet from 'gridjs-spreadsheet';
2
+ import type Spreadsheet, { SemanticAutomationOptions } from 'gridjs-spreadsheet';
3
3
  import type { GridJsAdapter } from './shared';
4
4
 
5
5
  export interface GridJsSpreadsheetProps {
@@ -12,6 +12,7 @@ export interface GridJsSpreadsheetProps {
12
12
  height?: string | number;
13
13
  showToolbar?: boolean;
14
14
  showContextmenu?: boolean;
15
+ semanticAutomation?: SemanticAutomationOptions;
15
16
  className?: string;
16
17
  style?: CSSProperties;
17
18
  onReady?: (instance: Spreadsheet, adapter: GridJsAdapter) => void;
package/react.js CHANGED
@@ -22,6 +22,7 @@ export function GridJsSpreadsheet({
22
22
  height = 'calc(100vh - 96px)',
23
23
  showToolbar = true,
24
24
  showContextmenu = true,
25
+ semanticAutomation,
25
26
  className = 'gridjs-react-host',
26
27
  style,
27
28
  onReady,
@@ -54,6 +55,7 @@ export function GridJsSpreadsheet({
54
55
  token,
55
56
  showToolbar,
56
57
  showContextmenu,
58
+ semanticAutomation,
57
59
  callbacks: {
58
60
  ready: onReady,
59
61
  change: onChange,
@@ -88,7 +90,7 @@ export function GridJsSpreadsheet({
88
90
  adapterRef.current = null;
89
91
  if (hostRef.current) hostRef.current.innerHTML = '';
90
92
  };
91
- }, [apiBase, dataKey, loader, mode, locale, token, showToolbar, showContextmenu]);
93
+ }, [apiBase, dataKey, loader, mode, locale, token, showToolbar, showContextmenu, semanticAutomation]);
92
94
 
93
95
  useEffect(() => {
94
96
  if (adapterRef.current && token) {
package/readme.md CHANGED
@@ -393,6 +393,12 @@ Modern browsers — Chrome, Firefox, Safari, Edge.
393
393
 
394
394
  ## Version History
395
395
 
396
+ <details>
397
+ <summary><strong>v26.8.1</strong> — Support redaction for search matches</summary>
398
+
399
+ - Support redaction for search matches
400
+ </details>
401
+
396
402
  <details>
397
403
  <summary><strong>v26.8</strong> — Support redaction for entire sheet</summary>
398
404
 
package/shared.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type Spreadsheet from 'gridjs-spreadsheet';
1
+ import type Spreadsheet, { SemanticAutomationOptions } from 'gridjs-spreadsheet';
2
2
 
3
3
  export interface GridJsEndpoints {
4
4
  updateCell: string;
@@ -48,6 +48,7 @@ export interface GridJsAdapterConfig {
48
48
  fileName?: string;
49
49
  basicZorder?: number;
50
50
  view?: Record<string, any>;
51
+ semanticAutomation?: SemanticAutomationOptions;
51
52
  callbacks?: GridJsAdapterCallbacks;
52
53
  dependencies?: GridJsAdapterDependencies;
53
54
  }
package/shared.js CHANGED
@@ -119,6 +119,7 @@ function buildSpreadsheetOptions(config, endpoints) {
119
119
  ...(config.token ? { token: config.token } : {}),
120
120
  ...(config.loadingGif ? { loadingGif: config.loadingGif } : {}),
121
121
  ...(config.view ? { view: config.view } : {}),
122
+ ...(config.semanticAutomation ? { semanticAutomation: config.semanticAutomation } : {}),
122
123
  };
123
124
  }
124
125
 
package/vue.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { DefineComponent } from 'vue';
2
- import type Spreadsheet from 'gridjs-spreadsheet';
2
+ import type Spreadsheet, { SemanticAutomationOptions } from 'gridjs-spreadsheet';
3
3
  import type { GridJsAdapter } from './shared';
4
4
 
5
5
  export interface GridJsSpreadsheetProps {
@@ -12,6 +12,7 @@ export interface GridJsSpreadsheetProps {
12
12
  height?: string | number;
13
13
  showToolbar?: boolean;
14
14
  showContextmenu?: boolean;
15
+ semanticAutomation?: SemanticAutomationOptions;
15
16
  }
16
17
 
17
18
  export declare const GridJsSpreadsheet: DefineComponent<GridJsSpreadsheetProps, {}, any>;
package/vue.js CHANGED
@@ -30,6 +30,7 @@ export const GridJsSpreadsheet = defineComponent({
30
30
  height: { type: [String, Number], default: 'calc(100vh - 96px)' },
31
31
  showToolbar: { type: Boolean, default: true },
32
32
  showContextmenu: { type: Boolean, default: true },
33
+ semanticAutomation: { type: Object, default: null },
33
34
  },
34
35
  emits: [
35
36
  'ready',
@@ -59,6 +60,7 @@ export const GridJsSpreadsheet = defineComponent({
59
60
  token: props.token,
60
61
  showToolbar: props.showToolbar,
61
62
  showContextmenu: props.showContextmenu,
63
+ semanticAutomation: props.semanticAutomation,
62
64
  callbacks: {
63
65
  ready: (instance, activeAdapter) => emit('ready', instance, activeAdapter),
64
66
  change: (...args) => emit('change', ...args),
@@ -84,6 +86,7 @@ export const GridJsSpreadsheet = defineComponent({
84
86
  props.locale,
85
87
  props.showToolbar,
86
88
  props.showContextmenu,
89
+ props.semanticAutomation,
87
90
  ],
88
91
  () => {
89
92
  mountGridJs().catch(error => emit('error', { type: 'mountError', error }));
package/xspreadsheet.css CHANGED
@@ -21,6 +21,7 @@ body {
21
21
  .x-spreadsheet-workspace {
22
22
  display: grid;
23
23
  width: 100%;
24
+ min-height: 0;
24
25
  grid-template-columns: minmax(0, 1fr) 0;
25
26
  align-items: stretch;
26
27
  overflow: hidden;
@@ -30,6 +31,7 @@ body {
30
31
  }
31
32
  .x-spreadsheet-workspace-sheet-pane {
32
33
  min-width: 0;
34
+ min-height: 0;
33
35
  overflow: hidden;
34
36
  }
35
37
  .x-spreadsheet-workspace-sheet-pane > .x-spreadsheet-bottombar {
@@ -42,6 +44,7 @@ body {
42
44
  display: flex;
43
45
  width: 100%;
44
46
  min-width: 0;
47
+ min-height: 0;
45
48
  flex-direction: column;
46
49
  align-self: stretch;
47
50
  box-sizing: border-box;
@@ -65,6 +68,7 @@ body {
65
68
  }
66
69
  .x-spreadsheet-format-panel-header {
67
70
  display: flex;
71
+ flex: 0 0 52px;
68
72
  min-height: 52px;
69
73
  align-items: center;
70
74
  justify-content: space-between;
@@ -112,6 +116,7 @@ body {
112
116
  }
113
117
  .x-spreadsheet-format-panel-tabs {
114
118
  display: flex;
119
+ flex: 0 0 56px;
115
120
  min-height: 56px;
116
121
  align-items: stretch;
117
122
  justify-content: center;
@@ -154,11 +159,37 @@ body {
154
159
  background: #2f7d50;
155
160
  }
156
161
  .x-spreadsheet-format-panel-body {
157
- flex: 1;
162
+ flex: 1 1 0;
163
+ height: 0;
164
+ min-height: 0;
158
165
  box-sizing: border-box;
159
- overflow: auto;
166
+ padding-bottom: 24px;
167
+ overflow-x: hidden;
168
+ overflow-y: auto;
169
+ overscroll-behavior: contain;
170
+ scroll-padding-bottom: 24px;
171
+ scrollbar-color: #a7adb5 #f3f4f6;
172
+ scrollbar-gutter: stable;
173
+ scrollbar-width: thin;
174
+ -webkit-overflow-scrolling: touch;
160
175
  background: #fff;
161
176
  }
177
+ .x-spreadsheet-format-panel-body::-webkit-scrollbar {
178
+ width: 10px;
179
+ }
180
+ .x-spreadsheet-format-panel-body::-webkit-scrollbar-track {
181
+ background: #f3f4f6;
182
+ }
183
+ .x-spreadsheet-format-panel-body::-webkit-scrollbar-thumb {
184
+ background: #a7adb5;
185
+ background-clip: padding-box;
186
+ border: 2px solid #f3f4f6;
187
+ border-radius: 999px;
188
+ }
189
+ .x-spreadsheet-format-panel-body::-webkit-scrollbar-thumb:hover {
190
+ background: #858d97;
191
+ background-clip: padding-box;
192
+ }
162
193
  .x-spreadsheet-format-panel-empty-title {
163
194
  margin: 24px 20px 6px;
164
195
  font-size: 14px;
@@ -306,6 +337,123 @@ body {
306
337
  margin: 14px 0;
307
338
  background: #d6d9dd;
308
339
  }
340
+ .x-spreadsheet-format-panel-fill-editor {
341
+ display: flex;
342
+ flex-direction: column;
343
+ gap: 12px;
344
+ }
345
+ .x-spreadsheet-format-panel-select {
346
+ width: 100%;
347
+ min-width: 0;
348
+ height: 36px;
349
+ box-sizing: border-box;
350
+ padding: 0 30px 0 10px;
351
+ color: #27313d;
352
+ font: inherit;
353
+ font-size: 13px;
354
+ background: #fff;
355
+ border: 1px solid #9aa1a9;
356
+ border-radius: 5px;
357
+ }
358
+ .x-spreadsheet-format-panel-select:hover:not(:disabled),
359
+ .x-spreadsheet-format-panel-select:focus-visible {
360
+ border-color: #217346;
361
+ box-shadow: 0 0 0 2px rgba(33, 115, 70, 0.14);
362
+ outline: none;
363
+ }
364
+ .x-spreadsheet-format-panel-select:disabled {
365
+ color: #89939f;
366
+ background: #f1f3f5;
367
+ border-color: #d4d8dd;
368
+ cursor: not-allowed;
369
+ }
370
+ .x-spreadsheet-format-panel-texture-trigger {
371
+ display: inline-flex;
372
+ width: 82px;
373
+ height: 42px;
374
+ align-items: center;
375
+ justify-self: end;
376
+ justify-content: space-between;
377
+ box-sizing: border-box;
378
+ padding: 4px 10px 4px 5px;
379
+ color: #27313d;
380
+ background: #fff;
381
+ border: 1px solid #8f969e;
382
+ border-radius: 6px;
383
+ cursor: pointer;
384
+ }
385
+ .x-spreadsheet-format-panel-texture-trigger:hover:not(:disabled),
386
+ .x-spreadsheet-format-panel-texture-trigger:focus-visible {
387
+ border-color: #217346;
388
+ box-shadow: 0 0 0 2px rgba(33, 115, 70, 0.14);
389
+ outline: none;
390
+ }
391
+ .x-spreadsheet-format-panel-texture-trigger:disabled {
392
+ cursor: not-allowed;
393
+ opacity: 0.48;
394
+ }
395
+ .x-spreadsheet-format-panel-texture-trigger-preview,
396
+ .x-spreadsheet-format-panel-texture-preview {
397
+ display: block;
398
+ flex: 0 0 auto;
399
+ background-image: url(d022c86edc5b2d12a8d3d4890df3bebb.jpg);
400
+ background-repeat: no-repeat;
401
+ background-size: 500% 500%;
402
+ }
403
+ .x-spreadsheet-format-panel-texture-trigger-preview {
404
+ width: 32px;
405
+ height: 32px;
406
+ border: 1px solid #c5c9ce;
407
+ }
408
+ .x-spreadsheet-format-panel-texture-trigger-arrow {
409
+ width: 7px;
410
+ height: 7px;
411
+ border-right: 1.5px solid currentColor;
412
+ border-bottom: 1.5px solid currentColor;
413
+ transform: translateY(-2px) rotate(45deg);
414
+ }
415
+ .x-spreadsheet-format-panel-texture-gallery {
416
+ display: none;
417
+ grid-template-columns: repeat(5, 64px);
418
+ gap: 4px;
419
+ box-sizing: border-box;
420
+ padding: 8px;
421
+ background: #fff;
422
+ border: 1px solid #8f969e;
423
+ border-radius: 6px;
424
+ box-shadow: 0 10px 28px rgba(31, 42, 55, 0.24);
425
+ }
426
+ .x-spreadsheet-format-panel-texture-option {
427
+ width: 64px;
428
+ height: 64px;
429
+ box-sizing: border-box;
430
+ padding: 2px;
431
+ background: #fff;
432
+ border: 1px solid transparent;
433
+ border-radius: 2px;
434
+ cursor: pointer;
435
+ }
436
+ .x-spreadsheet-format-panel-texture-option:hover,
437
+ .x-spreadsheet-format-panel-texture-option:focus-visible {
438
+ border-color: #66707a;
439
+ outline: none;
440
+ }
441
+ .x-spreadsheet-format-panel-texture-option.x-spreadsheet-format-panel-texture-option-selected {
442
+ border-color: #217346;
443
+ box-shadow: inset 0 0 0 1px #217346;
444
+ }
445
+ .x-spreadsheet-format-panel-texture-preview {
446
+ width: 58px;
447
+ height: 58px;
448
+ }
449
+ .x-spreadsheet-format-panel-unsupported-fill {
450
+ padding: 9px 10px;
451
+ color: #5f6874;
452
+ font-size: 12px;
453
+ line-height: 18px;
454
+ background: #f6f7f8;
455
+ border-radius: 4px;
456
+ }
309
457
  .x-spreadsheet-format-panel-label {
310
458
  min-width: 0;
311
459
  color: #374151;
@@ -378,6 +526,69 @@ body {
378
526
  .x-spreadsheet-format-panel-color-control {
379
527
  justify-self: end;
380
528
  }
529
+ .x-spreadsheet-format-panel-transparency-control {
530
+ display: grid;
531
+ min-width: 0;
532
+ grid-template-columns: minmax(58px, 1fr) 82px;
533
+ align-items: center;
534
+ gap: 8px;
535
+ }
536
+ .x-spreadsheet-format-panel-transparency-range {
537
+ width: 100%;
538
+ min-width: 0;
539
+ accent-color: #217346;
540
+ cursor: pointer;
541
+ }
542
+ .x-spreadsheet-format-panel-transparency-range:disabled {
543
+ cursor: not-allowed;
544
+ opacity: 0.5;
545
+ }
546
+ .x-spreadsheet-format-panel-percent-control {
547
+ width: 82px;
548
+ min-width: 0;
549
+ }
550
+ .x-spreadsheet-format-panel-pattern-label {
551
+ color: #374151;
552
+ font-size: 13px;
553
+ line-height: 18px;
554
+ }
555
+ .x-spreadsheet-format-panel-pattern-gallery {
556
+ display: grid;
557
+ grid-template-columns: repeat(6, 34px);
558
+ gap: 5px;
559
+ }
560
+ .x-spreadsheet-format-panel-pattern-button {
561
+ display: inline-flex;
562
+ width: 34px;
563
+ height: 30px;
564
+ align-items: center;
565
+ justify-content: center;
566
+ box-sizing: border-box;
567
+ padding: 1px;
568
+ overflow: hidden;
569
+ background: #fff;
570
+ border: 1px solid transparent;
571
+ border-radius: 2px;
572
+ cursor: pointer;
573
+ }
574
+ .x-spreadsheet-format-panel-pattern-button:hover:not(:disabled),
575
+ .x-spreadsheet-format-panel-pattern-button:focus-visible {
576
+ border-color: #7c8794;
577
+ outline: none;
578
+ }
579
+ .x-spreadsheet-format-panel-pattern-button:disabled {
580
+ cursor: not-allowed;
581
+ opacity: 0.48;
582
+ }
583
+ .x-spreadsheet-format-panel-pattern-button-selected {
584
+ border-color: #217346;
585
+ box-shadow: 0 0 0 1px #217346;
586
+ }
587
+ .x-spreadsheet-format-panel-pattern-preview {
588
+ display: block;
589
+ width: 30px;
590
+ height: 24px;
591
+ }
381
592
  .x-spreadsheet-format-panel-color-button {
382
593
  display: inline-flex;
383
594
  width: 72px;
@@ -454,6 +665,9 @@ body {
454
665
  .x-spreadsheet-format-panel-color-control {
455
666
  justify-self: start;
456
667
  }
668
+ .x-spreadsheet-format-panel-transparency-control {
669
+ width: 100%;
670
+ }
457
671
  .x-spreadsheet-format-panel-error {
458
672
  grid-column: 1;
459
673
  }
@@ -2581,11 +2795,27 @@ form fieldset select {
2581
2795
  display: inline-block;
2582
2796
  }
2583
2797
  .x-spreadsheet-icon .x-spreadsheet-icon-img {
2584
- background-image: url(9667af4182f3e39eec9844c10e1a6eb8.svg);
2798
+ background-image: url(544d1ebaa4cddf566b9f3c24186b9873.svg);
2585
2799
  position: absolute;
2586
2800
  width: 262px;
2587
2801
  height: 444px;
2588
2802
  opacity: 0.86;
2803
+ /*
2804
+ // Search & Redact icon (text-based, no sprite dependency)
2805
+ &.searchRedact {
2806
+ background-image: none;
2807
+ width: auto;
2808
+ height: auto;
2809
+ &::before {
2810
+ content: '🔍';
2811
+ font-size: 14px;
2812
+ line-height: 18px;
2813
+ color: #555;
2814
+ display: block;
2815
+ text-align: center;
2816
+ }
2817
+ }
2818
+ */
2589
2819
  }
2590
2820
  .x-spreadsheet-icon .x-spreadsheet-icon-img.undo {
2591
2821
  left: 0;
@@ -2717,6 +2947,10 @@ form fieldset select {
2717
2947
  display: block;
2718
2948
  text-align: center;
2719
2949
  }
2950
+ .x-spreadsheet-icon .x-spreadsheet-icon-img.searchRedact {
2951
+ left: -180px;
2952
+ top: -126px;
2953
+ }
2720
2954
  .x-spreadsheet-icon .x-spreadsheet-icon-img.autofilter {
2721
2955
  left: -90px;
2722
2956
  top: -18px;