@swiftbrowser/web 0.5.5 → 0.5.6
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.
- package/package.json +1 -1
- package/src/layout/engine.ts +30 -5
- package/src/layoutDom.ts +70 -10
- package/src/styles.css +17 -0
- package/src/symbols.ts +191 -0
package/package.json
CHANGED
package/src/layout/engine.ts
CHANGED
|
@@ -1932,8 +1932,22 @@ export class LayoutPass {
|
|
|
1932
1932
|
rowY += PICKER_INLINE_ROW_HEIGHT;
|
|
1933
1933
|
}
|
|
1934
1934
|
} else {
|
|
1935
|
-
|
|
1936
|
-
|
|
1935
|
+
// Too little room for both: as an HStack shares it, the narrower of
|
|
1936
|
+
// the two is offered half first and keeps what it needs; the other
|
|
1937
|
+
// takes the rest and truncates (a long value, rather than its label).
|
|
1938
|
+
const room = Math.max(0, size.width - PICKER_MENU_GAP);
|
|
1939
|
+
let labelWidth = plan.labelWidth;
|
|
1940
|
+
let valueWidth = plan.valueWidth;
|
|
1941
|
+
if (labelWidth + valueWidth > room) {
|
|
1942
|
+
if (labelWidth <= valueWidth) {
|
|
1943
|
+
labelWidth = Math.min(labelWidth, room / 2);
|
|
1944
|
+
valueWidth = room - labelWidth;
|
|
1945
|
+
} else {
|
|
1946
|
+
valueWidth = Math.min(valueWidth, room / 2);
|
|
1947
|
+
labelWidth = room - valueWidth;
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
valueWidth = Math.min(valueWidth, size.width);
|
|
1937
1951
|
chrome['label'] = { x, y, width: labelWidth, height: size.height };
|
|
1938
1952
|
chrome['value'] = { x: x + size.width - valueWidth, y, width: valueWidth, height: size.height };
|
|
1939
1953
|
}
|
|
@@ -2606,10 +2620,21 @@ export class LayoutPass {
|
|
|
2606
2620
|
case 'image':
|
|
2607
2621
|
if (node.id >= 0) this.fonts.set(node.id, scaledFont(ctx.font, ctx.imageScale));
|
|
2608
2622
|
return;
|
|
2609
|
-
case 'textfield':
|
|
2610
|
-
// A
|
|
2611
|
-
|
|
2623
|
+
case 'textfield': {
|
|
2624
|
+
// A field draws its text in the context font, so it sits on the same
|
|
2625
|
+
// baseline as a label in that font beside it (a form row's).
|
|
2626
|
+
if (node.id < 0) return;
|
|
2627
|
+
this.fonts.set(node.id, ctx.font);
|
|
2628
|
+
if (node.props['axis'] === 'vertical') return;
|
|
2629
|
+
// Where a one-line Text centered in the field would sit: snapped with
|
|
2630
|
+
// the frames, it lands where a label centered beside the field does,
|
|
2631
|
+
// and the DOM puts the field's text there (layoutDom.ts). Keep the
|
|
2632
|
+
// list row chrome a list set before placing.
|
|
2633
|
+
const line = ctx.font.lineHeight;
|
|
2634
|
+
const existing = this.chrome.get(node.id);
|
|
2635
|
+
this.setChrome(node, { ...existing, text: { x, y: y + (size.height - line) / 2, width: size.width, height: line } });
|
|
2612
2636
|
return;
|
|
2637
|
+
}
|
|
2613
2638
|
case 'spacer':
|
|
2614
2639
|
case 'lazyspacer':
|
|
2615
2640
|
case 'divider':
|
package/src/layoutDom.ts
CHANGED
|
@@ -363,18 +363,68 @@ function setFlag(el: HTMLElement, key: string, value: string | null): void {
|
|
|
363
363
|
}
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
-
/**
|
|
367
|
-
|
|
366
|
+
/**
|
|
367
|
+
* For leaf rows: pad the content frame back into place inside the row box.
|
|
368
|
+
* `shift` moves vertically centered content (a one-line field's text) down
|
|
369
|
+
* (or up, negative) by padding twice as much above it (or below).
|
|
370
|
+
*/
|
|
371
|
+
function padIntoFrame(el: HTMLElement, box: Rect, frame: Rect, shift = 0): void {
|
|
368
372
|
const s = el.style;
|
|
369
373
|
const left = frame.x - box.x;
|
|
370
374
|
const top = frame.y - box.y;
|
|
371
375
|
const right = box.x + box.width - (frame.x + frame.width);
|
|
372
376
|
const bottom = box.y + box.height - (frame.y + frame.height);
|
|
377
|
+
const above = Math.max(0, top) + Math.max(0, 2 * shift);
|
|
378
|
+
const below = Math.max(0, bottom) + Math.max(0, -2 * shift);
|
|
373
379
|
if (left || top || right || bottom) {
|
|
374
|
-
s.padding = `${
|
|
375
|
-
|
|
376
|
-
s.padding = '';
|
|
380
|
+
s.padding = `${above}px ${Math.max(0, right)}px ${below}px ${Math.max(0, left)}px`;
|
|
381
|
+
return;
|
|
377
382
|
}
|
|
383
|
+
// Only the shift: above and below alone, the sides left to the stylesheet
|
|
384
|
+
// (a rounded border field's inset).
|
|
385
|
+
if (s.paddingLeft || s.paddingRight) s.padding = '';
|
|
386
|
+
const paddingTop = above ? `${above}px` : '';
|
|
387
|
+
const paddingBottom = below ? `${below}px` : '';
|
|
388
|
+
if (s.paddingTop !== paddingTop) s.paddingTop = paddingTop;
|
|
389
|
+
if (s.paddingBottom !== paddingBottom) s.paddingBottom = paddingBottom;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const fieldCapShifts = new Map<string, number>();
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* How far a one-line field's text must move so its capitals sit where a
|
|
396
|
+
* text's do: styles.css trims a text's first line to its cap height and puts
|
|
397
|
+
* the capitals `--sb-cap-inset` (SF Pro's 0.2476em) below the line's top,
|
|
398
|
+
* whatever font the page has, but an input lays its line out with the
|
|
399
|
+
* font's own metrics. Where those put the capitals is measured in the page
|
|
400
|
+
* (canvas may resolve a font list to another face): a line trimmed to its
|
|
401
|
+
* cap height is shorter than an untrimmed one by just that. Once per font;
|
|
402
|
+
* none where texts are not trimmed (both then use the font's metrics).
|
|
403
|
+
*/
|
|
404
|
+
function fieldCapShift(font: ResolvedFont): number {
|
|
405
|
+
const cached = fieldCapShifts.get(font.css);
|
|
406
|
+
if (cached !== undefined) return cached;
|
|
407
|
+
let shift = 0;
|
|
408
|
+
if (typeof CSS !== 'undefined' && CSS.supports('text-box', 'trim-start cap alphabetic') && document.body) {
|
|
409
|
+
const probe = document.createElement('div');
|
|
410
|
+
probe.style.cssText = 'position:absolute;left:-9999px;top:0;visibility:hidden;white-space:pre';
|
|
411
|
+
const line = (trimmed: boolean): HTMLElement => {
|
|
412
|
+
const el = document.createElement('div');
|
|
413
|
+
el.style.font = font.css;
|
|
414
|
+
if (trimmed) el.style.setProperty('text-box', 'trim-start cap alphabetic');
|
|
415
|
+
el.textContent = 'H';
|
|
416
|
+
return probe.appendChild(el);
|
|
417
|
+
};
|
|
418
|
+
const whole = line(false);
|
|
419
|
+
const trimmed = line(true);
|
|
420
|
+
document.body.appendChild(probe);
|
|
421
|
+
const natural = whole.getBoundingClientRect().height - trimmed.getBoundingClientRect().height;
|
|
422
|
+
probe.remove();
|
|
423
|
+
shift = Math.round((0.2476 * font.size - natural) * 100) / 100;
|
|
424
|
+
}
|
|
425
|
+
// a web font still loading measures as its fallback: measure again next time
|
|
426
|
+
if (typeof document === 'undefined' || !document.fonts || document.fonts.status === 'loaded') fieldCapShifts.set(font.css, shift);
|
|
427
|
+
return shift;
|
|
378
428
|
}
|
|
379
429
|
|
|
380
430
|
function applyChrome(
|
|
@@ -419,12 +469,22 @@ function applyChrome(
|
|
|
419
469
|
return;
|
|
420
470
|
}
|
|
421
471
|
case 'textfield':
|
|
422
|
-
case 'texteditor':
|
|
423
|
-
// A
|
|
424
|
-
// a leading apart.
|
|
425
|
-
|
|
426
|
-
|
|
472
|
+
case 'texteditor': {
|
|
473
|
+
// A field draws in its context's font (a vertical one, the font its
|
|
474
|
+
// lines were measured in, a leading apart).
|
|
475
|
+
const font = result.fonts.get(node.id);
|
|
476
|
+
setFont(el, font, el instanceof HTMLTextAreaElement ? 2 : 1);
|
|
477
|
+
// A one-line field's text sits where a centered Text's would (the
|
|
478
|
+
// engine's `text` rect, snapped as a label beside it is): the input
|
|
479
|
+
// centers its line in the frame, so move it by the difference.
|
|
480
|
+
const line = chrome?.['text'];
|
|
481
|
+
const shift =
|
|
482
|
+
el instanceof HTMLInputElement && font
|
|
483
|
+
? fieldCapShift(font) + (line ? line.y - frame.y - (frame.height - font.lineHeight) / 2 : 0)
|
|
484
|
+
: 0;
|
|
485
|
+
padIntoFrame(el, box, frame, shift);
|
|
427
486
|
return;
|
|
487
|
+
}
|
|
428
488
|
// Phase 8 controls: their chrome sits at the engine's rects inside the element's box.
|
|
429
489
|
case 'stepper':
|
|
430
490
|
placeChrome(el.querySelector<HTMLElement>(':scope > .sb-stepper-control'), chrome?.['control'], box);
|
package/src/styles.css
CHANGED
|
@@ -716,12 +716,29 @@ svg[data-sb-symbol="progress.indicator"] > line:nth-child(8) { animation-delay:
|
|
|
716
716
|
font: inherit;
|
|
717
717
|
font-size: var(--sb-font-size-body);
|
|
718
718
|
line-height: 1.3;
|
|
719
|
+
/* the text starts at the field's edge, as SwiftUI's does (no UA padding) */
|
|
720
|
+
padding: 0;
|
|
721
|
+
/* `.multilineTextAlignment` reaches fields as it reaches text (inputs reset it) */
|
|
722
|
+
text-align: inherit;
|
|
719
723
|
color: var(--sb-color-primary);
|
|
720
724
|
background: transparent;
|
|
721
725
|
border: 0;
|
|
722
726
|
outline: none;
|
|
723
727
|
}
|
|
724
728
|
|
|
729
|
+
/* `.multilineTextAlignment` on a view: the fields inside inherit it (texts set their own). */
|
|
730
|
+
[data-sb-text-align="leading"] {
|
|
731
|
+
text-align: left;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
[data-sb-text-align="center"] {
|
|
735
|
+
text-align: center;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
[data-sb-text-align="trailing"] {
|
|
739
|
+
text-align: right;
|
|
740
|
+
}
|
|
741
|
+
|
|
725
742
|
.sb-textfield::placeholder {
|
|
726
743
|
color: var(--sb-color-placeholder);
|
|
727
744
|
}
|
package/src/symbols.ts
CHANGED
|
@@ -421,6 +421,48 @@ import {
|
|
|
421
421
|
ZoomIn,
|
|
422
422
|
ZoomOut,
|
|
423
423
|
createElement,
|
|
424
|
+
AlignCenterHorizontal,
|
|
425
|
+
AlignCenterVertical,
|
|
426
|
+
AlignHorizontalDistributeCenter,
|
|
427
|
+
AlignStartHorizontal,
|
|
428
|
+
AlignStartVertical,
|
|
429
|
+
Box,
|
|
430
|
+
Braces,
|
|
431
|
+
CircleDashed,
|
|
432
|
+
Club,
|
|
433
|
+
Columns3,
|
|
434
|
+
CornerDownRight,
|
|
435
|
+
CornerUpLeft,
|
|
436
|
+
CornerUpRight,
|
|
437
|
+
Dice1,
|
|
438
|
+
Dice2,
|
|
439
|
+
Dice3,
|
|
440
|
+
Dice4,
|
|
441
|
+
Dice5,
|
|
442
|
+
Dice6,
|
|
443
|
+
Diff,
|
|
444
|
+
Divide,
|
|
445
|
+
Equal,
|
|
446
|
+
FastForward,
|
|
447
|
+
FlipHorizontal2,
|
|
448
|
+
FlipVertical2,
|
|
449
|
+
Layers2,
|
|
450
|
+
MemoryStick,
|
|
451
|
+
Move3d,
|
|
452
|
+
PinOff,
|
|
453
|
+
Radical,
|
|
454
|
+
Rewind,
|
|
455
|
+
Rotate3d,
|
|
456
|
+
RotateCcwSquare,
|
|
457
|
+
RotateCwSquare,
|
|
458
|
+
Scale3d,
|
|
459
|
+
Signature,
|
|
460
|
+
SlidersVertical,
|
|
461
|
+
Spade,
|
|
462
|
+
Table,
|
|
463
|
+
Tablet,
|
|
464
|
+
TextCursor,
|
|
465
|
+
Waves,
|
|
424
466
|
type IconNode,
|
|
425
467
|
} from 'lucide';
|
|
426
468
|
|
|
@@ -467,6 +509,70 @@ const SQUARE_ON_CIRCLE_FILL: IconNode = [
|
|
|
467
509
|
['rect', { x: '9', y: '9', width: '13', height: '13', rx: '3', stroke: KNOCKOUT_COLOR, 'stroke-width': '2.4' }],
|
|
468
510
|
];
|
|
469
511
|
|
|
512
|
+
/**
|
|
513
|
+
* A numeral in a circle or rounded square (`1.circle`, `1.square.fill`):
|
|
514
|
+
* lucide has none, so the numeral is drawn in its stroke style, the
|
|
515
|
+
* enclosure the size `enclosed` gives other glyphs'.
|
|
516
|
+
*/
|
|
517
|
+
const NUMERALS: Readonly<Record<string, IconNode>> = {
|
|
518
|
+
// each about 5 wide and 9 high, centered on the glyph's middle
|
|
519
|
+
'0': [['rect', { x: '9.5', y: '7.5', width: '5', height: '9', rx: '2.5' }]],
|
|
520
|
+
// a stem with a flag at its top, as lucide's `Heading1` draws its 1
|
|
521
|
+
'1': [['path', { d: 'M9.5 9.5 12.5 7.5v9' }]],
|
|
522
|
+
'2': [['path', { d: 'M9.5 9.75a2.5 2.5 0 0 1 5 0c0 1.4-.9 2.4-2 3.5L9.5 16.5h5' }]],
|
|
523
|
+
'3': [['path', { d: 'M9.5 7.5h5L12 11a2.75 2.75 0 1 1-1.94 4.69' }]],
|
|
524
|
+
'4': [['path', { d: 'M13.5 16.5v-9L9 13.5h6' }]],
|
|
525
|
+
'5': [['path', { d: 'M14.5 7.5H10l-.5 4.25c.7-.5 1.5-.75 2.5-.75a2.75 2.75 0 0 1 0 5.5c-1 0-2-.5-2.5-1.25' }]],
|
|
526
|
+
'6': [
|
|
527
|
+
['path', { d: 'M14 7.5c-2.5 1-4.5 3.5-4.5 6.5' }],
|
|
528
|
+
['circle', { cx: '12', cy: '14', r: '2.5' }],
|
|
529
|
+
],
|
|
530
|
+
'7': [['path', { d: 'M9.5 7.5h5l-3.5 9' }]],
|
|
531
|
+
'8': [
|
|
532
|
+
['circle', { cx: '12', cy: '9.5', r: '2' }],
|
|
533
|
+
['circle', { cx: '12', cy: '14', r: '2.5' }],
|
|
534
|
+
],
|
|
535
|
+
'9': [
|
|
536
|
+
['circle', { cx: '12', cy: '10', r: '2.5' }],
|
|
537
|
+
['path', { d: 'M14.5 10c0 3-2 5.5-4.5 6.5' }],
|
|
538
|
+
],
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
function numeral(digit: string, enclosure: 'circle' | 'square'): IconNode {
|
|
542
|
+
const outer: IconNode[number] =
|
|
543
|
+
enclosure === 'circle' ? ['circle', { cx: '12', cy: '12', r: '10' }] : ['rect', { x: '3', y: '3', width: '18', height: '18', rx: '4' }];
|
|
544
|
+
return [outer, ...NUMERALS[digit]!];
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/** `0.circle` … `9.square.fill`: every numeral, in a circle or a square, outlined or filled. */
|
|
548
|
+
const NUMERAL_SYMBOLS: Record<string, SymbolGlyph> = Object.fromEntries(
|
|
549
|
+
Object.keys(NUMERALS).flatMap((digit) =>
|
|
550
|
+
(['circle', 'square'] as const).flatMap((enclosure) => [
|
|
551
|
+
[`${digit}.${enclosure}`, { icon: numeral(digit, enclosure), fill: 'outline' }],
|
|
552
|
+
[`${digit}.${enclosure}.fill`, { icon: numeral(digit, enclosure), fill: 'knockout' }],
|
|
553
|
+
]),
|
|
554
|
+
),
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
/** `info`: the i on its own (lucide draws it only in a circle), a foot under its stem. */
|
|
558
|
+
const INFO: IconNode = [
|
|
559
|
+
['path', { d: 'M10 10h2v10' }],
|
|
560
|
+
['path', { d: 'M9.5 20h5' }],
|
|
561
|
+
['path', { d: 'M12 5h.01' }],
|
|
562
|
+
];
|
|
563
|
+
|
|
564
|
+
/** `exclamationmark`: the mark on its own. */
|
|
565
|
+
const EXCLAMATIONMARK: IconNode = [
|
|
566
|
+
['path', { d: 'M12 4v11' }],
|
|
567
|
+
['path', { d: 'M12 20h.01' }],
|
|
568
|
+
];
|
|
569
|
+
|
|
570
|
+
/** `questionmark`: lucide's `CircleQuestionMark` mark on its own, scaled up to fill the glyph. */
|
|
571
|
+
const QUESTIONMARK: IconNode = [
|
|
572
|
+
['path', { d: 'M6.91 6.53a5.25 5.25 0 0 1 10.2 1.75c0 3.5-5.25 5.25-5.25 5.25' }],
|
|
573
|
+
['path', { d: 'M12 20.5h.01' }],
|
|
574
|
+
];
|
|
575
|
+
|
|
470
576
|
const outline = (icon: IconNode): SymbolGlyph => ({ icon, fill: 'outline' });
|
|
471
577
|
const knockout = (icon: IconNode): SymbolGlyph => ({ icon, fill: 'knockout' });
|
|
472
578
|
const solid = (icon: IconNode): SymbolGlyph => ({ icon, fill: 'solid' });
|
|
@@ -491,6 +597,7 @@ export const SF_SYMBOLS: Readonly<Record<string, SymbolGlyph>> = {
|
|
|
491
597
|
'minus.circle.fill': knockout(CircleMinus),
|
|
492
598
|
'info.circle': outline(Info),
|
|
493
599
|
'info.circle.fill': knockout(Info),
|
|
600
|
+
questionmark: outline(QUESTIONMARK),
|
|
494
601
|
'questionmark.circle': outline(CircleQuestionMark),
|
|
495
602
|
'questionmark.circle.fill': knockout(CircleQuestionMark),
|
|
496
603
|
'exclamationmark.circle': outline(CircleAlert),
|
|
@@ -506,6 +613,90 @@ export const SF_SYMBOLS: Readonly<Record<string, SymbolGlyph>> = {
|
|
|
506
613
|
'circle.fill': solid(Circle),
|
|
507
614
|
'circle.inset.filled': outline(CircleDot),
|
|
508
615
|
'largecircle.fill.circle': outline(CircleDot),
|
|
616
|
+
...NUMERAL_SYMBOLS,
|
|
617
|
+
// media, keys, math, dice and cards, layout and 3D tools, the bare info and exclamation marks
|
|
618
|
+
backward: outline(Rewind),
|
|
619
|
+
'backward.fill': solid(Rewind),
|
|
620
|
+
forward: outline(FastForward),
|
|
621
|
+
'forward.fill': solid(FastForward),
|
|
622
|
+
goforward: outline(RotateCw),
|
|
623
|
+
gobackward: outline(RotateCcw),
|
|
624
|
+
cube: outline(Box),
|
|
625
|
+
'cube.fill': outline(Box),
|
|
626
|
+
shift: outline(ArrowBigUp),
|
|
627
|
+
'shift.fill': solid(ArrowBigUp),
|
|
628
|
+
control: outline(ChevronUp),
|
|
629
|
+
curlybraces: outline(Braces),
|
|
630
|
+
equal: outline(Equal),
|
|
631
|
+
divide: outline(Divide),
|
|
632
|
+
multiply: outline(X),
|
|
633
|
+
plusminus: outline(Diff),
|
|
634
|
+
'x.squareroot': outline(Radical),
|
|
635
|
+
'die.face.1': outline(Dice1),
|
|
636
|
+
'die.face.2': outline(Dice2),
|
|
637
|
+
'die.face.3': outline(Dice3),
|
|
638
|
+
'die.face.4': outline(Dice4),
|
|
639
|
+
'die.face.5': outline(Dice5),
|
|
640
|
+
'die.face.6': outline(Dice6),
|
|
641
|
+
'die.face.1.fill': knockout(Dice1),
|
|
642
|
+
'die.face.2.fill': knockout(Dice2),
|
|
643
|
+
'die.face.3.fill': knockout(Dice3),
|
|
644
|
+
'die.face.4.fill': knockout(Dice4),
|
|
645
|
+
'die.face.5.fill': knockout(Dice5),
|
|
646
|
+
'die.face.6.fill': knockout(Dice6),
|
|
647
|
+
display: outline(Monitor),
|
|
648
|
+
ipad: outline(Tablet),
|
|
649
|
+
internaldrive: outline(HardDrive),
|
|
650
|
+
memorychip: outline(MemoryStick),
|
|
651
|
+
// lucide names its flips by the axis line: its FlipVertical2 mirrors left to right
|
|
652
|
+
'flip.horizontal': outline(FlipVertical2),
|
|
653
|
+
'flip.vertical': outline(FlipHorizontal2),
|
|
654
|
+
'rotate.left': outline(RotateCcwSquare),
|
|
655
|
+
'rotate.right': outline(RotateCwSquare),
|
|
656
|
+
'align.horizontal.left': outline(AlignStartVertical),
|
|
657
|
+
'align.horizontal.center': outline(AlignCenterVertical),
|
|
658
|
+
'align.vertical.top': outline(AlignStartHorizontal),
|
|
659
|
+
'align.vertical.center': outline(AlignCenterHorizontal),
|
|
660
|
+
'distribute.horizontal.center': outline(AlignHorizontalDistributeCenter),
|
|
661
|
+
'move.3d': outline(Move3d),
|
|
662
|
+
'rotate.3d': outline(Rotate3d),
|
|
663
|
+
'scale.3d': outline(Scale3d),
|
|
664
|
+
'square.2.layers.3d': outline(Layers2),
|
|
665
|
+
'square.3.layers.3d': outline(Layers3),
|
|
666
|
+
'square.3.stack.3d': outline(Layers),
|
|
667
|
+
'hand.point.up.left': outline(Pointer),
|
|
668
|
+
'pin.slash': outline(PinOff),
|
|
669
|
+
'square.dotted': outline(SquareDashed),
|
|
670
|
+
'rectangle.dashed': outline(SquareDashed),
|
|
671
|
+
'circle.dashed': outline(CircleDashed),
|
|
672
|
+
'rectangle.split.3x1': outline(Columns3),
|
|
673
|
+
tablecells: outline(Table),
|
|
674
|
+
'tablecells.fill': outline(Table),
|
|
675
|
+
signature: outline(Signature),
|
|
676
|
+
'sidebar.leading': outline(PanelLeft),
|
|
677
|
+
'sidebar.trailing': outline(PanelRight),
|
|
678
|
+
'slider.vertical.3': outline(SlidersVertical),
|
|
679
|
+
'suit.heart': outline(Heart),
|
|
680
|
+
'suit.heart.fill': solid(Heart),
|
|
681
|
+
'suit.club': outline(Club),
|
|
682
|
+
'suit.club.fill': solid(Club),
|
|
683
|
+
'suit.spade': outline(Spade),
|
|
684
|
+
'suit.spade.fill': solid(Spade),
|
|
685
|
+
'suit.diamond': outline(Diamond),
|
|
686
|
+
'suit.diamond.fill': solid(Diamond),
|
|
687
|
+
target: outline(Target),
|
|
688
|
+
'water.waves': outline(Waves),
|
|
689
|
+
'text.cursor': outline(TextCursor),
|
|
690
|
+
'arrow.turn.down.left': outline(CornerDownLeft),
|
|
691
|
+
'arrow.turn.down.right': outline(CornerDownRight),
|
|
692
|
+
'arrow.turn.up.left': outline(CornerUpLeft),
|
|
693
|
+
'arrow.turn.up.right': outline(CornerUpRight),
|
|
694
|
+
'chevron.compact.down': outline(ChevronDown),
|
|
695
|
+
'chevron.compact.up': outline(ChevronUp),
|
|
696
|
+
'chevron.compact.left': outline(ChevronLeft),
|
|
697
|
+
'chevron.compact.right': outline(ChevronRight),
|
|
698
|
+
info: outline(INFO),
|
|
699
|
+
exclamationmark: outline(EXCLAMATIONMARK),
|
|
509
700
|
square: outline(Square),
|
|
510
701
|
'square.fill': solid(Square),
|
|
511
702
|
star: outline(Star),
|