Refine routing rule controls and responsive layout
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
export const HARBOR_VERSIONS = Object.freeze({
|
||||
macClient: '0.26.0',
|
||||
gatewayClient: '0.27.0',
|
||||
macClient: '0.26.1',
|
||||
gatewayClient: '0.27.1',
|
||||
gatewayBackend: '0.27.0',
|
||||
});
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import { operationBlocked } from '../../state/operations.js';
|
||||
import { ConfirmationDialog } from '../../ui/ConfirmationDialog.js';
|
||||
import { Drawer } from '../../ui/Drawer.js';
|
||||
import { RailAction } from '../../ui/RailAction.js';
|
||||
import { Tooltip } from '../../ui/Tooltip.js';
|
||||
import {
|
||||
beginRuleReorder,
|
||||
crossedRuleIndex,
|
||||
@@ -760,19 +761,26 @@ function RuleOutboundPicker({
|
||||
disabled?: boolean;
|
||||
onChange: (value: RouteRule['outbound']) => void;
|
||||
}) {
|
||||
return <div className="client-rule-outbound" role="group" aria-label={`Маршрут правила ${index + 1}`}>
|
||||
{([['vpn', 'VPN'], ['direct', 'Напрямую']] as const).map(([outbound, label]) => (
|
||||
<button
|
||||
type="button"
|
||||
key={outbound}
|
||||
aria-pressed={value === outbound}
|
||||
disabled={disabled}
|
||||
onClick={() => onChange(outbound)}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>;
|
||||
const direct = value === 'direct';
|
||||
const label = direct ? 'Напрямую' : 'VPN';
|
||||
return <span className="client-rule-outbound client-tooltip-anchor">
|
||||
<button
|
||||
className={direct ? 'is-direct' : 'is-vpn'}
|
||||
type="button"
|
||||
aria-label={`Маршрут правила ${index + 1}: ${label}. Переключить на ${direct ? 'VPN' : 'Напрямую'}`}
|
||||
aria-pressed={direct}
|
||||
disabled={disabled}
|
||||
onClick={() => onChange(direct ? 'vpn' : 'direct')}
|
||||
>
|
||||
{direct ? <svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M4 12h15M14 7l5 5-5 5" />
|
||||
</svg> : <svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M12 3 19 6v5c0 4.4-2.8 8-7 10-4.2-2-7-5.6-7-10V6l7-3Z" />
|
||||
<path d="m9 12 2 2 4-4" />
|
||||
</svg>}
|
||||
</button>
|
||||
<Tooltip>{label}</Tooltip>
|
||||
</span>;
|
||||
}
|
||||
|
||||
export function RoutingToggle({
|
||||
@@ -899,7 +907,11 @@ export function RoutingPanel({ feature, statusSlot }: { feature: RoutingFeature;
|
||||
</span>
|
||||
<section className="client-local-rules-group" aria-labelledby="local-rules-list-title">
|
||||
<span id="local-rules-list-title">Правила</span>
|
||||
<div className="client-local-rules-list">
|
||||
<div
|
||||
className={`client-local-rules-list${draftRules.length > 1 ? ' has-order-flow' : ''}`}
|
||||
role="list"
|
||||
aria-label="Правила применяются сверху вниз"
|
||||
>
|
||||
{feature.rules.map((rule, index) => {
|
||||
const [status, statusLabel] = localRuleStatus(
|
||||
rule,
|
||||
@@ -916,6 +928,7 @@ export function RoutingPanel({ feature, statusSlot }: { feature: RoutingFeature;
|
||||
className={`client-local-rule client-deletable-row is-${status}${rule.enabled ? '' : ' is-disabled'}${rule.removing ? ' is-removing' : ''}${lifted ? ' is-dragging' : ''}`}
|
||||
key={rule._key}
|
||||
data-rule-key={rule._key}
|
||||
role="listitem"
|
||||
style={{ viewTransitionName: rule.removing ? 'none' : rule._key }}
|
||||
inert={rule.removing ? true : undefined}
|
||||
>
|
||||
@@ -974,6 +987,20 @@ export function RoutingPanel({ feature, statusSlot }: { feature: RoutingFeature;
|
||||
value={rule.value}
|
||||
onChange={(event) => feature.change(index, 'value', event.target.value)}
|
||||
/>
|
||||
<RuleOutboundPicker
|
||||
value={rule.outbound}
|
||||
index={index}
|
||||
disabled={editorDisabled}
|
||||
onChange={(outbound) => feature.change(index, 'outbound', outbound)}
|
||||
/>
|
||||
<span
|
||||
className="client-local-rule-status client-tooltip-anchor"
|
||||
role="status"
|
||||
aria-label={`Состояние правила: ${statusLabel}`}
|
||||
>
|
||||
<span className="client-rule-status-dot" aria-hidden="true" />
|
||||
<Tooltip>{statusLabel}</Tooltip>
|
||||
</span>
|
||||
<button
|
||||
className="client-row-delete"
|
||||
type="button"
|
||||
@@ -988,15 +1015,6 @@ export function RoutingPanel({ feature, statusSlot }: { feature: RoutingFeature;
|
||||
aria-hidden="true"
|
||||
onAnimationEnd={() => feature.finishRemove(rule._key)}
|
||||
/>
|
||||
<div className="client-local-rule-meta">
|
||||
<RuleOutboundPicker
|
||||
value={rule.outbound}
|
||||
index={index}
|
||||
disabled={editorDisabled}
|
||||
onChange={(outbound) => feature.change(index, 'outbound', outbound)}
|
||||
/>
|
||||
<span className="client-local-rule-status" role="status">{statusLabel}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -72,7 +72,32 @@
|
||||
}
|
||||
|
||||
.client-local-rules-list {
|
||||
gap: 2px;
|
||||
position: relative;
|
||||
gap: 0;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.client-local-rules-list.has-order-flow::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
bottom: 22px;
|
||||
left: 3px;
|
||||
width: 1px;
|
||||
background: linear-gradient(to bottom, transparent, color-mix(in oklch, var(--client-accent) 46%, transparent) 15%, color-mix(in oklch, var(--client-accent) 46%, transparent) 85%, transparent);
|
||||
box-shadow: 0 0 7px color-mix(in oklch, var(--client-accent) 24%, transparent);
|
||||
}
|
||||
|
||||
.client-local-rules-list.has-order-flow::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 18px;
|
||||
left: 0;
|
||||
width: 7px;
|
||||
height: 6px;
|
||||
background: color-mix(in oklch, var(--client-accent) 64%, transparent);
|
||||
clip-path: polygon(0 0, 100% 0, 50% 100%);
|
||||
filter: drop-shadow(0 0 4px color-mix(in oklch, var(--client-accent) 36%, transparent));
|
||||
}
|
||||
|
||||
.client-local-rule {
|
||||
@@ -81,36 +106,57 @@
|
||||
isolation: isolate;
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 44px 24px 116px minmax(0, 1fr) 28px;
|
||||
grid-template-columns: 44px 24px 104px minmax(84px, 1fr) 34px 16px 28px;
|
||||
align-items: center;
|
||||
column-gap: 8px;
|
||||
row-gap: 2px;
|
||||
padding: 7px 0;
|
||||
column-gap: 6px;
|
||||
padding: 4px 0;
|
||||
animation: client-row-enter 560ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
||||
transition: background-color 180ms ease, box-shadow 180ms ease, opacity 260ms ease, filter 360ms ease;
|
||||
}
|
||||
|
||||
.client-local-rule + .client-local-rule::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 44px;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, color-mix(in oklch, var(--client-muted) 24%, transparent), color-mix(in oklch, var(--client-muted) 9%, transparent) 72%, transparent);
|
||||
}
|
||||
|
||||
.client-local-rule:has(.client-rule-type.is-open) {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.client-local-rule-status {
|
||||
width: 16px;
|
||||
height: 44px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: var(--client-muted);
|
||||
font: var(--type-label);
|
||||
letter-spacing: var(--type-label-tracking);
|
||||
text-transform: var(--type-label-transform);
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
transition: color 280ms ease, opacity 280ms ease, filter 360ms ease;
|
||||
}
|
||||
|
||||
.client-local-rule.is-active .client-local-rule-status {
|
||||
.client-rule-status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
opacity: 0.58;
|
||||
transition: color 280ms ease, opacity 280ms ease, filter 360ms ease, transform 280ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.client-local-rule.is-active .client-rule-status-dot {
|
||||
color: var(--client-accent);
|
||||
opacity: 1;
|
||||
filter: drop-shadow(0 0 5px color-mix(in oklch, var(--client-accent) 52%, transparent));
|
||||
transform: scale(1.14);
|
||||
}
|
||||
|
||||
.client-local-rule.is-pending .client-local-rule-status,
|
||||
.client-local-rule.is-unsaved .client-local-rule-status {
|
||||
.client-local-rule.is-pending .client-rule-status-dot,
|
||||
.client-local-rule.is-unsaved .client-rule-status-dot {
|
||||
color: var(--client-warning, oklch(0.72 0.12 72));
|
||||
opacity: 1;
|
||||
filter: drop-shadow(0 0 4px color-mix(in oklch, var(--client-warning, oklch(0.72 0.12 72)) 44%, transparent));
|
||||
}
|
||||
|
||||
.client-local-rule.is-disabled > :not(.client-rule-handle):not(.client-row-delete):not(.client-delete-strike) {
|
||||
@@ -361,42 +407,39 @@
|
||||
text-shadow: 0 0 9px color-mix(in oklch, var(--client-accent) 22%, transparent);
|
||||
}
|
||||
|
||||
.client-local-rule-meta {
|
||||
min-width: 0;
|
||||
grid-column: 2 / -1;
|
||||
grid-row: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.client-rule-outbound {
|
||||
width: 128px;
|
||||
height: 30px;
|
||||
flex: 0 0 128px;
|
||||
display: grid;
|
||||
grid-template-columns: 48px minmax(0, 1fr);
|
||||
align-items: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.client-rule-outbound button {
|
||||
height: 30px;
|
||||
padding: 0 5px;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
color: var(--client-muted);
|
||||
font: var(--type-label);
|
||||
letter-spacing: var(--type-label-tracking);
|
||||
text-transform: var(--type-label-transform);
|
||||
cursor: pointer;
|
||||
transition: color 280ms ease, filter 280ms ease, text-shadow 280ms ease;
|
||||
transition: color 220ms ease, filter 320ms ease, background 220ms ease;
|
||||
}
|
||||
|
||||
.client-rule-outbound button[aria-pressed='true'] {
|
||||
.client-rule-outbound button.is-direct {
|
||||
color: var(--client-accent);
|
||||
filter: drop-shadow(0 0 6px color-mix(in oklch, var(--client-accent) 34%, transparent));
|
||||
text-shadow: 0 0 9px color-mix(in oklch, var(--client-accent) 28%, transparent);
|
||||
}
|
||||
|
||||
.client-rule-outbound svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.7;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.client-rule-outbound button:disabled {
|
||||
@@ -405,8 +448,25 @@
|
||||
|
||||
.client-rule-outbound button:focus-visible {
|
||||
outline: 0;
|
||||
background: color-mix(in oklch, var(--client-accent) 10%, transparent);
|
||||
color: var(--client-accent);
|
||||
text-shadow: 0 0 9px color-mix(in oklch, var(--client-accent) 42%, transparent);
|
||||
filter: drop-shadow(0 0 5px color-mix(in oklch, var(--client-accent) 36%, transparent));
|
||||
}
|
||||
|
||||
.client-rule-outbound button:hover:not(:disabled) {
|
||||
background: color-mix(in oklch, var(--client-accent) 10%, transparent);
|
||||
color: var(--client-accent);
|
||||
filter: drop-shadow(0 0 5px color-mix(in oklch, var(--client-accent) 36%, transparent));
|
||||
}
|
||||
|
||||
.client-rule-outbound button.is-direct:hover:not(:disabled) svg,
|
||||
.client-rule-outbound button.is-direct:focus-visible svg {
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
.client-rule-outbound button.is-vpn:hover:not(:disabled) svg,
|
||||
.client-rule-outbound button.is-vpn:focus-visible svg {
|
||||
transform: translateY(-1px) rotate(3deg) scale(1.05);
|
||||
}
|
||||
|
||||
.client-rule-reorder-instructions,
|
||||
|
||||
+44
-17
@@ -704,7 +704,9 @@
|
||||
}
|
||||
|
||||
.client-local-rule {
|
||||
grid-template-columns: 44px 44px minmax(0, 1fr) 44px;
|
||||
grid-template-columns: 44px 44px minmax(0, 1fr) 44px 44px;
|
||||
column-gap: 4px;
|
||||
row-gap: 0;
|
||||
}
|
||||
|
||||
.client-rule-handle,
|
||||
@@ -721,6 +723,10 @@
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.client-rule-outbound button {
|
||||
width: 44px;
|
||||
}
|
||||
|
||||
.client-rule-type-list button {
|
||||
min-height: 44px;
|
||||
}
|
||||
@@ -734,7 +740,11 @@
|
||||
}
|
||||
|
||||
.client-local-rule {
|
||||
gap: 8px;
|
||||
padding-block: 4px;
|
||||
}
|
||||
|
||||
.client-local-rules-list {
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.client-rule-handle {
|
||||
@@ -753,18 +763,27 @@
|
||||
}
|
||||
|
||||
.client-row-delete {
|
||||
grid-column: 4;
|
||||
grid-column: 5;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.client-local-rule input {
|
||||
grid-column: 2 / -1;
|
||||
grid-column: 2 / 5;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.client-local-rule-meta {
|
||||
grid-column: 2 / -1;
|
||||
grid-row: 3;
|
||||
.client-rule-outbound {
|
||||
grid-column: 4;
|
||||
grid-row: 1;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.client-local-rule-status {
|
||||
grid-column: 5;
|
||||
grid-row: 2;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.client-instruction-block:nth-child(n) {
|
||||
@@ -784,21 +803,29 @@
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.client-local-rule-meta {
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
.client-local-rule {
|
||||
grid-template-columns: 44px 44px minmax(0, 1fr) 44px;
|
||||
}
|
||||
|
||||
.client-rule-outbound {
|
||||
width: 100%;
|
||||
flex-basis: 100%;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
grid-column: 2;
|
||||
grid-row: 3;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.client-local-rule-status {
|
||||
width: 100%;
|
||||
min-height: 1em;
|
||||
text-align: left;
|
||||
white-space: normal;
|
||||
grid-column: 4;
|
||||
grid-row: 3;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.client-row-delete {
|
||||
grid-column: 4;
|
||||
}
|
||||
|
||||
.client-local-rule input {
|
||||
grid-column: 2 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +132,8 @@
|
||||
.client-rule-type-list button,
|
||||
.client-local-rule input,
|
||||
.client-rule-outbound button,
|
||||
.client-rule-outbound svg,
|
||||
.client-rule-status-dot,
|
||||
.client-row-delete,
|
||||
.client-row-add,
|
||||
.client-row-add-slot > span,
|
||||
|
||||
@@ -193,20 +193,23 @@ test('secondary menus share one right rail and switch equal drawers as a vertica
|
||||
assert.doesNotMatch(component, /instructionsFeature\.close\(\)[\s\S]{0,180}devicesFeature\.close\(\)[\s\S]{0,180}subscriptionFeature\.toggle\(\)/);
|
||||
});
|
||||
|
||||
test('routing rules keep two desktop rows and three narrow rows without shrinking drag targets', () => {
|
||||
assert.match(rule('.client-local-rule'), /grid-template-columns:\s*44px 24px 116px minmax\(0, 1fr\) 28px/);
|
||||
assert.match(rule('.client-local-rule-meta'), /grid-column:\s*2 \/ -1[\s\S]*grid-row:\s*2/);
|
||||
test('routing rules stay in one desktop row and reflow without shrinking drag targets', () => {
|
||||
assert.match(rule('.client-local-rule'), /grid-template-columns:\s*44px 24px 104px minmax\(84px, 1fr\) 34px 16px 28px/);
|
||||
assert.doesNotMatch(routing, /client-local-rule-meta/);
|
||||
assert.match(styles, /\.client-local-rules-list \{[\s\S]*position:\s*relative[\s\S]*padding-left:\s*14px/);
|
||||
assert.match(styles, /\.client-local-rules-list\.has-order-flow::after[\s\S]*clip-path:\s*polygon\(0 0, 100% 0, 50% 100%\)/);
|
||||
const mobile = /@media \(max-width: 560px\) \{([\s\S]*?)\n\}\s*$/.exec(layoutStyles)?.[1] || '';
|
||||
assert.match(mobile, /grid-template-columns:\s*44px 44px minmax\(0, 1fr\) 44px/);
|
||||
assert.match(mobile, /grid-template-columns:\s*44px 44px minmax\(0, 1fr\) 44px 44px/);
|
||||
assert.match(mobile, /\.client-local-rule input \{[\s\S]*grid-row:\s*2/);
|
||||
assert.match(mobile, /\.client-local-rule-meta \{[\s\S]*grid-row:\s*3/);
|
||||
assert.match(mobile, /\.client-rule-outbound \{[\s\S]*grid-column:\s*4;[\s\S]*grid-row:\s*1/);
|
||||
assert.match(mobile, /\.client-local-rule-status \{[\s\S]*grid-column:\s*5;[\s\S]*grid-row:\s*2/);
|
||||
assert.match(mobile, /\.client-rule-handle,[\s\S]*width:\s*44px;[\s\S]*height:\s*44px/);
|
||||
assert.match(mobile, /\.client-rule-type-trigger,[\s\S]*\.client-rule-outbound button \{[\s\S]*height:\s*44px/);
|
||||
assert.match(mobile, /\.client-rule-type-list button \{[\s\S]*min-height:\s*44px/);
|
||||
const compact = layoutStyles.slice(layoutStyles.indexOf('@media (max-width: 360px)'));
|
||||
assert.match(compact, /\.client-local-rule-meta \{[\s\S]*flex-wrap:\s*wrap/);
|
||||
assert.match(compact, /\.client-rule-outbound \{[\s\S]*width:\s*100%[\s\S]*flex-basis:\s*100%/);
|
||||
assert.match(compact, /\.client-local-rule-status \{[\s\S]*width:\s*100%[\s\S]*white-space:\s*normal/);
|
||||
assert.match(compact, /grid-template-columns:\s*44px 44px minmax\(0, 1fr\) 44px/);
|
||||
assert.match(compact, /\.client-rule-outbound \{[\s\S]*grid-column:\s*2;[\s\S]*grid-row:\s*3/);
|
||||
assert.match(compact, /\.client-local-rule-status \{[\s\S]*grid-column:\s*4;[\s\S]*grid-row:\s*3/);
|
||||
});
|
||||
|
||||
test('connectivity diagnostics render stable compact tables before the first run', () => {
|
||||
|
||||
@@ -99,7 +99,7 @@ test('copy feedback, drawers and Gateway access actions expose complete semantic
|
||||
assert.match(styles, /@media \(max-width: 560px\)[\s\S]*\.client-rule-handle,[\s\S]*\.client-local-rule-enabled,[\s\S]*\.client-row-delete \{[\s\S]*width: 44px;[\s\S]*height: 44px/);
|
||||
});
|
||||
|
||||
test('ordered rules use one accessible drag handle and a fixed two-target control', () => {
|
||||
test('ordered rules use one accessible drag handle and a compact icon route control', () => {
|
||||
assert.match(routing, /className="client-rule-handle"[\s\S]*type="button"[\s\S]*aria-label=\{`Переместить правило, позиция/);
|
||||
assert.match(routing, /aria-describedby="client-rule-reorder-instructions"[\s\S]*aria-pressed=\{lifted\}/);
|
||||
assert.match(routing, /onPointerDown=\{\(event\) => feature\.startPointerReorder\(event, rule\._key\)\}/);
|
||||
@@ -108,8 +108,16 @@ test('ordered rules use one accessible drag handle and a fixed two-target contro
|
||||
assert.match(routing, /<svg viewBox="0 0 12 28" aria-hidden="true">[\s\S]*<circle[\s\S]*<circle[\s\S]*<circle/);
|
||||
assert.match(routing, /client-rule-reorder-instructions[\s\S]*стрелки вверх и вниз[\s\S]*Escape отменяет/);
|
||||
assert.match(routing, /client-rule-reorder-live[\s\S]*aria-live="polite"/);
|
||||
assert.match(routing, /className="client-rule-outbound" role="group"[\s\S]*\['vpn', 'VPN'\][\s\S]*\['direct', 'Напрямую'\]/);
|
||||
assert.match(routing, /className="client-rule-outbound client-tooltip-anchor"[\s\S]*className=\{direct \? 'is-direct' : 'is-vpn'\}/);
|
||||
assert.match(routing, /Маршрут правила \$\{index \+ 1\}: \$\{label\}\. Переключить на/);
|
||||
assert.match(routing, /M4 12h15M14 7l5 5-5 5[\s\S]*M12 3 19 6v5/);
|
||||
assert.doesNotMatch(routing, /client-rule-outbound" role="group"/);
|
||||
assert.match(routing, /className=\{`client-local-rules-list\$\{draftRules\.length > 1 \? ' has-order-flow' : ''\}`\}[\s\S]*aria-label="Правила применяются сверху вниз"/);
|
||||
assert.match(routing, /className="client-rule-status-dot"/);
|
||||
assert.doesNotMatch(routing, />\s*[↑↓]\s*</);
|
||||
assert.match(styles, /\.client-rule-handle \{[\s\S]*width: 44px;[\s\S]*height: 44px;[\s\S]*touch-action: none/);
|
||||
assert.match(styles, /\.client-rule-outbound \{[\s\S]*width: 128px/);
|
||||
assert.match(styles, /\.client-rule-outbound \{[\s\S]*width: 34px/);
|
||||
assert.match(styles, /\.client-rule-outbound svg \{[\s\S]*width: 20px/);
|
||||
assert.match(styles, /\.client-local-rules-list\.has-order-flow::before[\s\S]*linear-gradient\(to bottom/);
|
||||
assert.match(styles, /\.client-local-rule \+ \.client-local-rule::before[\s\S]*linear-gradient\(90deg/);
|
||||
});
|
||||
|
||||
@@ -37,26 +37,26 @@ const expectedImports = [
|
||||
const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex');
|
||||
const acceptedLedger = {
|
||||
counts: {
|
||||
cascadeEdges: 856,
|
||||
cascadeEdges: 927,
|
||||
customProperties: 106,
|
||||
declarations: 3387,
|
||||
declarations: 3436,
|
||||
important: 0,
|
||||
keyframes: 49,
|
||||
media: 13,
|
||||
rules: 959,
|
||||
variableReferences: 829,
|
||||
rules: 971,
|
||||
variableReferences: 834,
|
||||
},
|
||||
hashes: {
|
||||
cascadeEdges: '0aa9651d9c84e6274ee5f64cd3151304b612aff0a06858c3d86d935996a36216',
|
||||
cascadeEdges: 'ea513313fc4cdfa85a5de74c76bdf06a00df1fc8f71825053b05f06684c7d6df',
|
||||
customProperties: '06f39794d72566c2b2f8e4a2354866a54dbdceac0a1fdf9ae2619aae9abf2f36',
|
||||
declarations: '09d0332d509ab6ae1d148a75ef5e931439eab7b29909529c8454382f02778fba',
|
||||
declarations: '0109c86e26e22898aec17aca2cf952edb88748499735c0fd2fd2163d7dd37dda',
|
||||
duplicateKeyframes: '4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945',
|
||||
duplicateSelectors: 'abdba98d777bbb19d76443af200ea2cc9018a11e5ef4ae2885ff2f5dd07ef178',
|
||||
duplicateSelectors: '8982145dba05b33bf1c93b2d54cfbe76305b276ff3c657aa020144016ada5848',
|
||||
keyframes: '9e78309512ed82b1e9f87c58aeff505dfcdb694fc30c8f54570d01dce13eb51a',
|
||||
ruleDeclarationSequences: '6e22245aef1e61fe8d56ad064d5e60d02696ec2af5446caacd66311973d5e02c',
|
||||
selectors: '6487fcc63dbe251f250b79dd1430542e366c598ce93208eebfe51c344dcac38a',
|
||||
variableReferences: 'f9899b21c75649b687ebd660de6e3781aade3345e1f5bac49b0f6e235f63947d',
|
||||
witnesses: '87efd05d7a1fd22bc4f421573b41a115a86b2587703266079f9c913e26c323c9',
|
||||
ruleDeclarationSequences: '60267f6fbf59602e9028a9be4d8b591e1cd3e999eb5b86ab4e129199fd1853ea',
|
||||
selectors: '9970cb8a580a9c57a3f39f7a801bef08e76a905ba8042deae58ac637b9769781',
|
||||
variableReferences: '54bf2dffb86a0c9fc42c3d309cada316f446b17d8e54ce3c89b1108adb6e3db6',
|
||||
witnesses: '0db2c977cfd7cd86209a972e02bcbca9c22722155a88ba789ccf2a395eae4cfa',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -209,7 +209,7 @@ test('client typography uses the shared semantic scale outside the token owner',
|
||||
|
||||
test('accepted stylesheet has pinned declaration, selector, keyframe, variable, and cascade ledgers', () => {
|
||||
const witnesses = readStyleWitnesses(root);
|
||||
assert.equal(witnesses.length, 838);
|
||||
assert.equal(witnesses.length, 845);
|
||||
assert.equal(witnesses.filter((witness) => witness.unknown || witness.ancestorUnknown).length, 0);
|
||||
const ledger = createStyleLedger(readStyleSource(root), { witnesses });
|
||||
assert.deepEqual(ledger.counts, acceptedLedger.counts);
|
||||
@@ -405,8 +405,8 @@ test('main owns one public stylesheet and the regrouped production CSS is determ
|
||||
assert.equal((main.match(/import ['"][^'"]+\.css['"]/g) || []).length, 1);
|
||||
|
||||
const assets = fs.readdirSync(path.join(root, 'dist/assets')).filter((file) => file.endsWith('.css'));
|
||||
assert.deepEqual(assets, ['index-BoF9kamK.css']);
|
||||
assert.deepEqual(assets, ['index-D1sDzEdb.css']);
|
||||
const built = fs.readFileSync(path.join(root, 'dist/assets', assets[0]));
|
||||
assert.equal(built.byteLength, 131216);
|
||||
assert.equal(sha256(built), '1cab733ed1ae385a808f2afe5666ecc2252b48808d69a20c85e148c5eb60b96f');
|
||||
assert.equal(built.byteLength, 133160);
|
||||
assert.equal(sha256(built), '165e6706c69d737a09b9cdde9d8211e94dbea49b3df42c8e5c9d194993e6b618');
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ test('all repeated client primitive consumers use the shared owners', () => {
|
||||
.map(({ source }) => source)
|
||||
.join('\n');
|
||||
|
||||
assert.equal((production.match(/<Tooltip\b/g) || []).length, 10);
|
||||
assert.equal((production.match(/<Tooltip\b/g) || []).length, 12);
|
||||
assert.equal((production.match(/<CopyButton\b/g) || []).length, 2);
|
||||
assert.equal((production.match(/<RailAction\b/g) || []).length, 5);
|
||||
assert.equal((production.match(/<Drawer\b/g) || []).length, 5);
|
||||
|
||||
Reference in New Issue
Block a user