Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/angular/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@simple-table/angular",
"version": "3.0.0-beta.18",
"version": "3.0.0-beta.19",
"main": "dist/cjs/index.js",
"module": "dist/index.es.js",
"types": "dist/types/angular/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simple-table-core",
"version": "3.0.0-beta.18",
"version": "3.0.0-beta.19",
"main": "dist/cjs/index.js",
"module": "dist/index.es.js",
"types": "dist/src/index.d.ts",
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/core/dom/DOMManager.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { COLUMN_EDIT_WIDTH } from "../../consts/general-consts";
import { SimpleTableConfig } from "../../types/SimpleTableConfig";

export interface DOMElements {
Expand Down Expand Up @@ -60,6 +61,11 @@ export class DOMManager {

const content = document.createElement("div");
content.className = "st-content";
// Match RenderOrchestrator so DimensionManager's first clientWidth read (before any render)
// already excludes the column editor strip when editColumns is on.
content.style.width = config.editColumns
? `calc(100% - ${COLUMN_EDIT_WIDTH}px)`
: "100%";

const headerContainer = document.createElement("div");
headerContainer.className = "st-header-container";
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/managers/DimensionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,23 @@ export class DimensionManager {

this.resizeObserver = new ResizeObserver(updateContainerWidth);
this.resizeObserver.observe(containerElement);

// Width updates from RO are deferred to rAF above; without a synchronous read,
// state stays 0 until the next frame (breaks autoExpand resize and stale header
// context). Reading here is outside the RO callback, so Chromium RO loop issues
// do not apply.
this.applyContainerWidthSync(containerElement);
}

private applyContainerWidthSync(containerElement: HTMLElement): void {
const w = containerElement.clientWidth;
if (w > 0 && w !== this.state.containerWidth) {
this.state = {
...this.state,
containerWidth: w,
};
this.notifySubscribers();
}
}

updateConfig(config: Partial<DimensionManagerConfig>): void {
Expand Down
49 changes: 38 additions & 11 deletions packages/core/src/styles/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -1494,21 +1494,25 @@ input {
cursor: default;
}

/* Position variants */
.st-dropdown-bottom-left {
margin-top: 4px;
/* Filter popover (and similar): nested .st-dropdown-content menus must not be clipped by the shell.
overflow:auto + max-height on the parent creates a scrollport that clips absolutely positioned
children (operator CustomSelect, date picker, etc.). */
.st-dropdown-content.st-dropdown-content--allow-descendant-overflow {
overflow: visible;
max-height: none;
}

.st-dropdown-bottom-right {
margin-top: 4px;
}

.st-dropdown-top-left {
margin-bottom: 4px;
/* Nested filter UI panels (absolute) stack above the fixed filter shell */
.st-filter-container .st-dropdown-content {
z-index: 101;
}

/* Position variants — vertical offset comes from JS (React Dropdown parity: +4px only) */
.st-dropdown-bottom-left,
.st-dropdown-bottom-right,
.st-dropdown-top-left,
.st-dropdown-top-right {
margin-bottom: 4px;
margin: 0;
}

/* Dropdown items */
Expand Down Expand Up @@ -1768,12 +1772,19 @@ input {
font-size: 0.9em;
font-weight: 500;
font-family: inherit;
appearance: none;
-webkit-appearance: none;
transition: background-color var(--st-transition-duration)
var(--st-transition-ease);
}
/* Keyboard only — avoids a stuck ring after mouse click (especially on bordered Clear) */
.st-filter-button:focus {
outline: none;
}

.st-filter-button:focus-visible {
outline: 2px solid var(--st-focus-ring-color);
outline-offset: -2px;
outline-offset: 2px;
}

/* Apply Button */
Expand Down Expand Up @@ -1825,6 +1836,9 @@ input {
justify-content: space-between;
gap: var(--st-spacing-medium);
outline: none;
appearance: none;
-webkit-appearance: none;
text-align: left;
transition: border-color var(--st-transition-duration)
var(--st-transition-ease);
}
Expand Down Expand Up @@ -1924,6 +1938,12 @@ input {
overflow: auto;
}

/* Enum rows: left-align checkbox + label (full-width row); default .st-checkbox-label is centered */
.st-enum-filter-options .st-checkbox-label {
justify-content: flex-start;
width: 100%;
}

/* Select All checkbox styling */
.st-enum-select-all {
padding-bottom: var(--st-spacing-small);
Expand All @@ -1948,6 +1968,13 @@ input {
user-select: none;
}

.st-enum-filter-options .st-enum-option-label {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}

/* No results message */
.st-enum-no-results {
padding: var(--st-spacing-medium);
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/styles/themes/modern-dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* - Dark gray base with lighter text for reduced eye strain
* - Hover states with subtle brightness changes
* - Generous padding (12px) for better readability
* - Rounded corners (8px) for a softer appearance
* - Rounded corners (4px) for a clean, compact appearance
* - Modern blue accent (#60a5fa) for interactive elements (lighter for dark mode)
* - High contrast text for accessibility
* - Lightweight visual hierarchy
Expand All @@ -14,7 +14,7 @@
*/
.theme-modern-dark {
/* Layout/Structure variables - Tighter, more compact */
--st-border-radius: 8px;
--st-border-radius: 4px;
--st-cell-padding: 12px;

/* Spacing variables - Reduced for cleaner look */
Expand Down Expand Up @@ -205,7 +205,7 @@

/* Cleaner pagination buttons - more compact */
.theme-modern-dark .st-page-btn {
border-radius: 6px;
border-radius: 4px;
font-size: 13px;
font-weight: 500;
color: #d1d5db;
Expand All @@ -229,7 +229,7 @@
/* Next/Prev buttons */
.theme-modern-dark .st-next-prev-btn {
padding: 6px 8px;
border-radius: 6px;
border-radius: 4px;
transition: all 0.15s ease;
margin-left: 4px;
flex-shrink: 0;
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/styles/themes/modern-light.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* - White backgrounds with minimal color variation
* - Hover states instead of alternating row colors
* - Generous padding (12px) for better readability
* - Rounded corners (8px) for a softer appearance
* - Rounded corners (4px) for a clean, compact appearance
* - Modern blue accent (#3b82f6) for interactive elements
* - High contrast text (#111827) for accessibility
* - Lightweight visual hierarchy
Expand All @@ -14,7 +14,7 @@
*/
.theme-modern-light {
/* Layout/Structure variables - Tighter, more compact */
--st-border-radius: 8px;
--st-border-radius: 4px;
--st-cell-padding: 12px;

/* Spacing variables - Reduced for cleaner look */
Expand Down Expand Up @@ -205,7 +205,7 @@

/* Cleaner pagination buttons - more compact */
.theme-modern-light .st-page-btn {
border-radius: 6px;
border-radius: 4px;
font-size: 13px;
font-weight: 500;
color: #374151;
Expand All @@ -229,7 +229,7 @@
/* Next/Prev buttons */
.theme-modern-light .st-next-prev-btn {
padding: 6px 8px;
border-radius: 6px;
border-radius: 4px;
transition: all 0.15s ease;
margin-left: 4px;
flex-shrink: 0;
Expand Down
21 changes: 17 additions & 4 deletions packages/core/src/utils/filters/createCustomSelect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,14 @@ export const createCustomSelect = (options: CreateCustomSelectOptions) => {
const selectedOption = selectOptions.find((opt) => opt.value === value);
valueSpan.textContent = selectedOption ? selectedOption.label : placeholder;

const arrowSpan = document.createElement("span");
arrowSpan.innerHTML = SELECT_ICON_SVG;
// Match React CustomSelect: SVG is a direct child of the trigger so `.st-custom-select-arrow`
// is the flex item (flex-shrink, rotate) — not an unstyled wrapper span.
const iconTemplate = document.createElement("template");
iconTemplate.innerHTML = SELECT_ICON_SVG.trim();
const arrowIcon = iconTemplate.content.firstElementChild as SVGElement;

trigger.appendChild(valueSpan);
trigger.appendChild(arrowSpan);
trigger.appendChild(arrowIcon);
container.appendChild(trigger);

const optionsContainer = document.createElement("div");
Expand Down Expand Up @@ -106,6 +109,7 @@ export const createCustomSelect = (options: CreateCustomSelectOptions) => {
children: optionsContainer,
containerRef,
mainBodyRef,
anchorElement: trigger,
onClose: () => {
setOpen(false);
},
Expand All @@ -116,7 +120,14 @@ export const createCustomSelect = (options: CreateCustomSelectOptions) => {

container.appendChild(dropdown.element);

const syncValueFromSelection = (optionValue: string) => {
value = optionValue;
const opt = selectOptions.find((o) => o.value === value);
valueSpan.textContent = opt ? opt.label : placeholder;
};

const handleOptionClick = (optionValue: string) => {
syncValueFromSelection(optionValue);
onChange(optionValue);
setOpen(false);
focusedIndex = -1;
Expand Down Expand Up @@ -152,7 +163,9 @@ export const createCustomSelect = (options: CreateCustomSelectOptions) => {
case "Enter":
event.preventDefault();
if (focusedIndex >= 0) {
onChange(selectOptions[focusedIndex].value);
const v = selectOptions[focusedIndex].value;
syncValueFromSelection(v);
onChange(v);
setOpen(false);
focusedIndex = -1;
renderOptions();
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/utils/filters/createDateFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export const createDateFilter = (options: CreateDateFilterOptions) => {
children: picker.element,
containerRef,
mainBodyRef,
anchorElement: input,
onClose: () => {
isOpen = false;
},
Expand Down
Loading
Loading