Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Display
Layout
Split
Unified
Real-time editor
Hide whitespace changes
Hide unchanged lines
Disable line wrap
Diff precision
Smart
Syntax
None
Change appearance
Process
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
Start container controller diff
Created
3 days ago
Diff expires
in 4 weeks
Clear
Export
Share
Explain
45 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
163 lines
Copy
102 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
205 lines
Copy
import { raf } from '@utils/helpers';
import { raf } from '@utils/helpers';
import { isRTL } from '@utils/rtl';
import { isRTL } from '@utils/rtl';
/**
/**
* Applied to the host while the label is being repositioned. The
* Applied to the host while the label is being repositioned. The
* component stylesheets style this class, so it must stay in sync with
* component stylesheets style this class, so it must stay in sync with
* the `skip-label-transition` selector in those files. Renaming it here
* the `skip-label-transition` selector in those files. Renaming it here
* requires renaming it there too.
* requires renaming it there too.
*/
*/
export const SKIP_LABEL_TRANSITION_CLASS = 'skip-label-transition';
export const SKIP_LABEL_TRANSITION_CLASS = 'skip-label-transition';
/**
/**
* Set on the host as an inline style. The component stylesheets declare
* Set on the host as an inline style. The component stylesheets declare
* this property and read it with `var()`, so it must stay in sync with
* this property and read it with `var()`, so it must stay in sync with
* the `--internal-start-container-adjustment` references in those files.
* the `--internal-start-container-adjustment` references in those files.
* Renaming it here requires renaming it there too.
* Renaming it here requires renaming it there too.
*/
*/
export const START_CONTAINER_ADJUSTMENT_VAR = '--internal-start-container-adjustment';
export const START_CONTAINER_ADJUSTMENT_VAR = '--internal-start-container-adjustment';
/**
/**
Copy
Copied
Copy
Copied
* A utility to measure
and update
the start
container width adjustment
* Set on the host as an inline style. The component stylesheets declare
* for
form components
(input, textarea, select) with `fill="outline"`
.
* this property and read it with `var()`, so it must stay in sync with
* This adjustment compensates for
the
start container width
when
* the `--internal-start-end-container-width` references in those files.
* positioning
floating/stacked labels
with
in
the outline border.
* Renaming it here requires renaming it there too.
*/
export const START_END_CONTAINER_WIDTH_VAR = '--internal-start-end-container-width';
/**
* A utility to measure
the start
and end containers of
form components
*
(input, textarea, select) with `fill="outline"`
and write the results
* to
the
host. The
start container width
offsets
floating/stacked labels
* so they line up
with
the outline border.
The combined start and end
* container width lets the floating label size itself to the full width
* of the outline while still being positioned relative to the control.
*
*
* Measurement is deferred with raf() to avoid forcing layout during
* Measurement is deferred with raf() to avoid forcing layout during
* component updates, and a ResizeObserver watches for dynamic width
* component updates, and a ResizeObserver watches for dynamic width
* changes (e.g., when web fonts load or async content changes).
* changes (e.g., when web fonts load or async content changes).
*
*
* @internal
* @internal
* @param el - The host element (ion-input, ion-textarea, or ion-select).
* @param el - The host element (ion-input, ion-textarea, or ion-select).
* @param getStartContainer - A callback that returns the start container element.
* @param getStartContainer - A callback that returns the start container element.
Copy
Copied
Copy
Copied
* @param
shouldApplyAdjustment
- A callback that determines whether the
adjustment
should be
applied
.
* @param getEndContainer - A callback that returns the end container element.
* @param
shouldMeasure
- A callback that determines whether the
containers
should be
measured
.
*/
*/
Copy
Copied
Copy
Copied
export const createStart
ContainerController = (
export const createStart
End
ContainerController = (
el: HTMLElement,
el: HTMLElement,
getStartContainer: () => HTMLElement | undefined,
getStartContainer: () => HTMLElement | undefined,
Copy
Copied
Copy
Copied
shouldApplyAdjustment
: () => boolean
getEndContainer: () => HTMLElement | undefined,
): Start
ContainerController => {
shouldMeasure
: () => boolean
): Start
End
ContainerController => {
let resizeObserver: ResizeObserver | undefined;
let resizeObserver: ResizeObserver | undefined;
Copy
Copied
Copy
Copied
let
observedContainer
: HTMLElement | undefined;
let
observedStartContainer: HTMLElement | undefined;
let observedEndContainer
: HTMLElement | undefined;
let measurementRaf: number | undefined;
let measurementRaf: number | undefined;
let transitionRaf: number | undefined;
let transitionRaf: number | undefined;
let appliedAdjustment: string | undefined;
let appliedAdjustment: string | undefined;
Copy
Copied
Copy
Copied
let appliedStartEndWidth: string | undefined;
const calculateAdjustment = (): string => {
const startSlot = getStartContainer();
if (!startSlot || !shouldApplyAdjustment()) {
return '';
}
Copy
Copied
Copy
Copied
/*
/*
* Round to one decimal place so fractional widths produce a stable
* Round to one decimal place so fractional widths produce a stable
* label offset
when
the start
container is added, removed, or resized.
* label offset
and width
when
a
container is added, removed, or resized.
*/
*/
const startContainerWidth =
startSlot
.getBoundingClientRect().width
;
const roundWidth = (width: number) => Math.round(width * 10) / 10;
const
roundedWidth = Math.round(startContainerWidth * 10) / 10;
const measureContainers = (): { adjustment: string; startEndWidth: string } => {
const startContainer = getStartContainer();
if (!startContainer || !shouldMeasure()) {
return { adjustment: '', startEndWidth: '' };
}
const startContainerWidth =
roundWidth(startContainer
.getBoundingClientRect().width
)
;
const
endContainerWidth = roundWidth(getEndContainer()?.getBoundingClientRect().width ?? 0);
const sign = isRTL(el) ? '' : '-';
const sign = isRTL(el) ? '' : '-';
Copy
Copied
Copy
Copied
return
roundedWidth
? `${sign}${
roundedWidth
}px` : '0px'
;
return
{
adjustment: startContainerWidth
? `${sign}${
startContainerWidth
}px` : '0px'
,
startEndWidth: `${roundWidth(startContainerWidth + endContainerWidth)}px`,
}
;
};
};
Copy
Copied
Copy
Copied
const
scheduleAdjustmentUpdate
= () => {
const
scheduleMeasurement
= () => {
// Return if there is already a measurement queued to avoid a flicker
// Return if there is already a measurement queued to avoid a flicker
if (measurementRaf !== undefined) {
if (measurementRaf !== undefined) {
return;
return;
}
}
/*
/*
* Defer the measurement until the next animation frame so layout
* Defer the measurement until the next animation frame so layout
* is measured after the current update has been applied.
* is measured after the current update has been applied.
*/
*/
measurementRaf = raf(() => {
measurementRaf = raf(() => {
measurementRaf = undefined;
measurementRaf = undefined;
Copy
Copied
Copy
Copied
const
adjustment
= calculateAdjustment();
const
{
adjustment
, startEndWidth } = measureContainers();
/*
* The width only changes how much of the label fits, so it can
* animate. The transition is not suppressed here because the end
* container can change size while the label is floating, such as
* when async content loads, and that should not cut the float short.
*/
if (startEndWidth !== appliedStartEndWidth) {
el.style.setProperty(START_END_CONTAINER_WIDTH_VAR, startEndWidth);
appliedStartEndWidth = startEndWidth;
}
// Only suppress the label transition when the label has to move
// Only suppress the label transition when the label has to move
if (adjustment !== appliedAdjustment) {
if (adjustment !== appliedAdjustment) {
// Discard a removal queued by an earlier change
// Discard a removal queued by an earlier change
if (transitionRaf !== undefined) {
if (transitionRaf !== undefined) {
cancelAnimationFrame(transitionRaf);
cancelAnimationFrame(transitionRaf);
}
}
el.classList.add(SKIP_LABEL_TRANSITION_CLASS);
el.classList.add(SKIP_LABEL_TRANSITION_CLASS);
el.style.setProperty(START_CONTAINER_ADJUSTMENT_VAR, adjustment);
el.style.setProperty(START_CONTAINER_ADJUSTMENT_VAR, adjustment);
appliedAdjustment = adjustment;
appliedAdjustment = adjustment;
// Re-enable the transition once the new offset has been painted
// Re-enable the transition once the new offset has been painted
transitionRaf = raf(() => {
transitionRaf = raf(() => {
transitionRaf = undefined;
transitionRaf = undefined;
el.classList.remove(SKIP_LABEL_TRANSITION_CLASS);
el.classList.remove(SKIP_LABEL_TRANSITION_CLASS);
});
});
}
}
setupResizeObserver();
setupResizeObserver();
});
});
};
};
const disconnectResizeObserver = () => {
const disconnectResizeObserver = () => {
if (resizeObserver) {
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver.disconnect();
resizeObserver = undefined;
resizeObserver = undefined;
Copy
Copied
Copy
Copied
observedContainer
= undefined;
observedStartContainer = undefined;
observedEndContainer
= undefined;
}
}
};
};
const setupResizeObserver = () => {
const setupResizeObserver = () => {
Copy
Copied
Copy
Copied
const
startSlot
= getStartContainer();
const
startContainer
= getStartContainer();
const endContainer = getEndContainer();
Copy
Copied
Copy
Copied
// Stop watching once the
adjustment
no longer appl
ies
// Stop watching once the
measurements
no longer appl
y
if (!
startSlot
|| !
shouldApplyAdjustment
()) {
if (!
startContainer
|| !
shouldMeasure
()) {
disconnectResizeObserver();
disconnectResizeObserver();
return;
return;
}
}
Copy
Copied
Copy
Copied
// Return when prerendering or already watching th
is
container
// Return when prerendering or already watching th
ese
container
s
if (
typeof ResizeObserver !== 'function' ||
(resizeObserver && observed
Container ===
startSlot)
) {
if (
typeof ResizeObserver !== 'function' ||
(resizeObserver && observed
Start
Container ===
startContainer && observedEndContainer === endContainer)
) {
return;
return;
}
}
disconnectResizeObserver();
disconnectResizeObserver();
resizeObserver = new ResizeObserver(() => {
resizeObserver = new ResizeObserver(() => {
Copy
Copied
Copy
Copied
scheduleAdjustmentUpdate
();
scheduleMeasurement
();
});
});
Copy
Copied
Copy
Copied
observed
Container =
startSlot
;
observed
Start
Container =
startContainer
;
resizeObserver.observe(
startSlot);
resizeObserver.observe(
startContainer);
if (endContainer) {
observedEndContainer = endContainer;
resizeObserver.observe(endContainer);
}
};
};
Copy
Copied
Copy
Copied
const calculate
Start
ContainerWidth
= () => {
const calculate
ContainerWidth
s
= () => {
scheduleAdjustmentUpdate
();
scheduleMeasurement
();
};
};
const destroy = () => {
const destroy = () => {
disconnectResizeObserver();
disconnectResizeObserver();
if (measurementRaf !== undefined) {
if (measurementRaf !== undefined) {
cancelAnimationFrame(measurementRaf);
cancelAnimationFrame(measurementRaf);
measurementRaf = undefined;
measurementRaf = undefined;
}
}
// Tearing down mid-toggle would leave the transition disabled
// Tearing down mid-toggle would leave the transition disabled
if (transitionRaf !== undefined) {
if (transitionRaf !== undefined) {
cancelAnimationFrame(transitionRaf);
cancelAnimationFrame(transitionRaf);
transitionRaf = undefined;
transitionRaf = undefined;
el.classList.remove(SKIP_LABEL_TRANSITION_CLASS);
el.classList.remove(SKIP_LABEL_TRANSITION_CLASS);
}
}
// Re-apply from scratch if the element is connected again
// Re-apply from scratch if the element is connected again
appliedAdjustment = undefined;
appliedAdjustment = undefined;
Copy
Copied
Copy
Copied
appliedStartEndWidth = undefined;
};
};
return {
return {
Copy
Copied
Copy
Copied
calculate
Start
ContainerWidth
,
calculate
ContainerWidth
s
,
destroy,
destroy,
};
};
};
};
Copy
Copied
Copy
Copied
export type Start
ContainerController = {
export type Start
End
ContainerController = {
calculate
Start
ContainerWidth
: () => void;
calculate
ContainerWidth
s
: () => void;
destroy: () => void;
destroy: () => void;
};
};
Saved diffs
Original text
Open file
import { raf } from '@utils/helpers'; import { isRTL } from '@utils/rtl'; /** * Applied to the host while the label is being repositioned. The * component stylesheets style this class, so it must stay in sync with * the `skip-label-transition` selector in those files. Renaming it here * requires renaming it there too. */ export const SKIP_LABEL_TRANSITION_CLASS = 'skip-label-transition'; /** * Set on the host as an inline style. The component stylesheets declare * this property and read it with `var()`, so it must stay in sync with * the `--internal-start-container-adjustment` references in those files. * Renaming it here requires renaming it there too. */ export const START_CONTAINER_ADJUSTMENT_VAR = '--internal-start-container-adjustment'; /** * A utility to measure and update the start container width adjustment * for form components (input, textarea, select) with `fill="outline"`. * This adjustment compensates for the start container width when * positioning floating/stacked labels within the outline border. * * Measurement is deferred with raf() to avoid forcing layout during * component updates, and a ResizeObserver watches for dynamic width * changes (e.g., when web fonts load or async content changes). * * @internal * @param el - The host element (ion-input, ion-textarea, or ion-select). * @param getStartContainer - A callback that returns the start container element. * @param shouldApplyAdjustment - A callback that determines whether the adjustment should be applied. */ export const createStartContainerController = ( el: HTMLElement, getStartContainer: () => HTMLElement | undefined, shouldApplyAdjustment: () => boolean ): StartContainerController => { let resizeObserver: ResizeObserver | undefined; let observedContainer: HTMLElement | undefined; let measurementRaf: number | undefined; let transitionRaf: number | undefined; let appliedAdjustment: string | undefined; const calculateAdjustment = (): string => { const startSlot = getStartContainer(); if (!startSlot || !shouldApplyAdjustment()) { return ''; } /* * Round to one decimal place so fractional widths produce a stable * label offset when the start container is added, removed, or resized. */ const startContainerWidth = startSlot.getBoundingClientRect().width; const roundedWidth = Math.round(startContainerWidth * 10) / 10; const sign = isRTL(el) ? '' : '-'; return roundedWidth ? `${sign}${roundedWidth}px` : '0px'; }; const scheduleAdjustmentUpdate = () => { // Return if there is already a measurement queued to avoid a flicker if (measurementRaf !== undefined) { return; } /* * Defer the measurement until the next animation frame so layout * is measured after the current update has been applied. */ measurementRaf = raf(() => { measurementRaf = undefined; const adjustment = calculateAdjustment(); // Only suppress the label transition when the label has to move if (adjustment !== appliedAdjustment) { // Discard a removal queued by an earlier change if (transitionRaf !== undefined) { cancelAnimationFrame(transitionRaf); } el.classList.add(SKIP_LABEL_TRANSITION_CLASS); el.style.setProperty(START_CONTAINER_ADJUSTMENT_VAR, adjustment); appliedAdjustment = adjustment; // Re-enable the transition once the new offset has been painted transitionRaf = raf(() => { transitionRaf = undefined; el.classList.remove(SKIP_LABEL_TRANSITION_CLASS); }); } setupResizeObserver(); }); }; const disconnectResizeObserver = () => { if (resizeObserver) { resizeObserver.disconnect(); resizeObserver = undefined; observedContainer = undefined; } }; const setupResizeObserver = () => { const startSlot = getStartContainer(); // Stop watching once the adjustment no longer applies if (!startSlot || !shouldApplyAdjustment()) { disconnectResizeObserver(); return; } // Return when prerendering or already watching this container if (typeof ResizeObserver !== 'function' || (resizeObserver && observedContainer === startSlot)) { return; } disconnectResizeObserver(); resizeObserver = new ResizeObserver(() => { scheduleAdjustmentUpdate(); }); observedContainer = startSlot; resizeObserver.observe(startSlot); }; const calculateStartContainerWidth = () => { scheduleAdjustmentUpdate(); }; const destroy = () => { disconnectResizeObserver(); if (measurementRaf !== undefined) { cancelAnimationFrame(measurementRaf); measurementRaf = undefined; } // Tearing down mid-toggle would leave the transition disabled if (transitionRaf !== undefined) { cancelAnimationFrame(transitionRaf); transitionRaf = undefined; el.classList.remove(SKIP_LABEL_TRANSITION_CLASS); } // Re-apply from scratch if the element is connected again appliedAdjustment = undefined; }; return { calculateStartContainerWidth, destroy, }; }; export type StartContainerController = { calculateStartContainerWidth: () => void; destroy: () => void; };
Changed text
Open file
import { raf } from '@utils/helpers'; import { isRTL } from '@utils/rtl'; /** * Applied to the host while the label is being repositioned. The * component stylesheets style this class, so it must stay in sync with * the `skip-label-transition` selector in those files. Renaming it here * requires renaming it there too. */ export const SKIP_LABEL_TRANSITION_CLASS = 'skip-label-transition'; /** * Set on the host as an inline style. The component stylesheets declare * this property and read it with `var()`, so it must stay in sync with * the `--internal-start-container-adjustment` references in those files. * Renaming it here requires renaming it there too. */ export const START_CONTAINER_ADJUSTMENT_VAR = '--internal-start-container-adjustment'; /** * Set on the host as an inline style. The component stylesheets declare * this property and read it with `var()`, so it must stay in sync with * the `--internal-start-end-container-width` references in those files. * Renaming it here requires renaming it there too. */ export const START_END_CONTAINER_WIDTH_VAR = '--internal-start-end-container-width'; /** * A utility to measure the start and end containers of form components * (input, textarea, select) with `fill="outline"` and write the results * to the host. The start container width offsets floating/stacked labels * so they line up with the outline border. The combined start and end * container width lets the floating label size itself to the full width * of the outline while still being positioned relative to the control. * * Measurement is deferred with raf() to avoid forcing layout during * component updates, and a ResizeObserver watches for dynamic width * changes (e.g., when web fonts load or async content changes). * * @internal * @param el - The host element (ion-input, ion-textarea, or ion-select). * @param getStartContainer - A callback that returns the start container element. * @param getEndContainer - A callback that returns the end container element. * @param shouldMeasure - A callback that determines whether the containers should be measured. */ export const createStartEndContainerController = ( el: HTMLElement, getStartContainer: () => HTMLElement | undefined, getEndContainer: () => HTMLElement | undefined, shouldMeasure: () => boolean ): StartEndContainerController => { let resizeObserver: ResizeObserver | undefined; let observedStartContainer: HTMLElement | undefined; let observedEndContainer: HTMLElement | undefined; let measurementRaf: number | undefined; let transitionRaf: number | undefined; let appliedAdjustment: string | undefined; let appliedStartEndWidth: string | undefined; /* * Round to one decimal place so fractional widths produce a stable * label offset and width when a container is added, removed, or resized. */ const roundWidth = (width: number) => Math.round(width * 10) / 10; const measureContainers = (): { adjustment: string; startEndWidth: string } => { const startContainer = getStartContainer(); if (!startContainer || !shouldMeasure()) { return { adjustment: '', startEndWidth: '' }; } const startContainerWidth = roundWidth(startContainer.getBoundingClientRect().width); const endContainerWidth = roundWidth(getEndContainer()?.getBoundingClientRect().width ?? 0); const sign = isRTL(el) ? '' : '-'; return { adjustment: startContainerWidth ? `${sign}${startContainerWidth}px` : '0px', startEndWidth: `${roundWidth(startContainerWidth + endContainerWidth)}px`, }; }; const scheduleMeasurement = () => { // Return if there is already a measurement queued to avoid a flicker if (measurementRaf !== undefined) { return; } /* * Defer the measurement until the next animation frame so layout * is measured after the current update has been applied. */ measurementRaf = raf(() => { measurementRaf = undefined; const { adjustment, startEndWidth } = measureContainers(); /* * The width only changes how much of the label fits, so it can * animate. The transition is not suppressed here because the end * container can change size while the label is floating, such as * when async content loads, and that should not cut the float short. */ if (startEndWidth !== appliedStartEndWidth) { el.style.setProperty(START_END_CONTAINER_WIDTH_VAR, startEndWidth); appliedStartEndWidth = startEndWidth; } // Only suppress the label transition when the label has to move if (adjustment !== appliedAdjustment) { // Discard a removal queued by an earlier change if (transitionRaf !== undefined) { cancelAnimationFrame(transitionRaf); } el.classList.add(SKIP_LABEL_TRANSITION_CLASS); el.style.setProperty(START_CONTAINER_ADJUSTMENT_VAR, adjustment); appliedAdjustment = adjustment; // Re-enable the transition once the new offset has been painted transitionRaf = raf(() => { transitionRaf = undefined; el.classList.remove(SKIP_LABEL_TRANSITION_CLASS); }); } setupResizeObserver(); }); }; const disconnectResizeObserver = () => { if (resizeObserver) { resizeObserver.disconnect(); resizeObserver = undefined; observedStartContainer = undefined; observedEndContainer = undefined; } }; const setupResizeObserver = () => { const startContainer = getStartContainer(); const endContainer = getEndContainer(); // Stop watching once the measurements no longer apply if (!startContainer || !shouldMeasure()) { disconnectResizeObserver(); return; } // Return when prerendering or already watching these containers if ( typeof ResizeObserver !== 'function' || (resizeObserver && observedStartContainer === startContainer && observedEndContainer === endContainer) ) { return; } disconnectResizeObserver(); resizeObserver = new ResizeObserver(() => { scheduleMeasurement(); }); observedStartContainer = startContainer; resizeObserver.observe(startContainer); if (endContainer) { observedEndContainer = endContainer; resizeObserver.observe(endContainer); } }; const calculateContainerWidths = () => { scheduleMeasurement(); }; const destroy = () => { disconnectResizeObserver(); if (measurementRaf !== undefined) { cancelAnimationFrame(measurementRaf); measurementRaf = undefined; } // Tearing down mid-toggle would leave the transition disabled if (transitionRaf !== undefined) { cancelAnimationFrame(transitionRaf); transitionRaf = undefined; el.classList.remove(SKIP_LABEL_TRANSITION_CLASS); } // Re-apply from scratch if the element is connected again appliedAdjustment = undefined; appliedStartEndWidth = undefined; }; return { calculateContainerWidths, destroy, }; }; export type StartEndContainerController = { calculateContainerWidths: () => void; destroy: () => void; };
Find difference