leafer-ui 1.0.0-rc.5 → 1.0.0-rc.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/README.md CHANGED
@@ -4,7 +4,7 @@ Leafer UI 是基于 Leafer 开发的一套绚丽多彩的 UI 绘图框架,可
4
4
 
5
5
  提供了常用的 UI 绘图组件,和开箱即用的功能,方便与 Figma、Sketch 等产品进行数据交换,并为跨平台开发提供了统一、丰富的交互事件,如拖拽、旋转、缩放手势等。
6
6
 
7
- 1.0.0-rc.5 已发布 🎉🎉🎉,查看 [更新日志](https://leaferjs.com/ui/update/)。
7
+ 1.0.0-rc.6 已发布 🎉🎉🎉,查看 [更新日志](https://leaferjs.com/ui/update/)。
8
8
 
9
9
  目前产品已经逐步稳定,正式版即将到来,感谢所有参与的朋友们~
10
10
 
package/dist/web.esm.js CHANGED
@@ -558,7 +558,7 @@ class Renderer {
558
558
  }
559
559
 
560
560
  const { hitRadiusPoint } = BoundsHelper;
561
- class FindPath {
561
+ class Pather {
562
562
  constructor(target, selector) {
563
563
  this.target = target;
564
564
  this.selector = selector;
@@ -678,117 +678,108 @@ class FindPath {
678
678
  class Selector {
679
679
  constructor(target, userConfig) {
680
680
  this.config = {};
681
- this.innerIdList = {};
682
- this.idList = {};
683
- this.classNameList = {};
684
- this.tagNameList = {};
681
+ this.innerIdMap = {};
682
+ this.idMap = {};
683
+ this.methods = {
684
+ id: (leaf, name) => leaf.id === name ? this.idMap[name] = leaf : 0,
685
+ innerId: (leaf, innerId) => leaf.innerId === innerId ? this.innerIdMap[innerId] = leaf : 0,
686
+ className: (leaf, name) => leaf.className === name ? 1 : 0,
687
+ tag: (leaf, name) => leaf.__tag === name ? 1 : 0
688
+ };
685
689
  this.target = target;
686
690
  if (userConfig)
687
691
  this.config = DataHelper.default(userConfig, this.config);
688
- this.findPath = new FindPath(target, this);
692
+ this.pather = new Pather(target, this);
689
693
  this.__listenEvents();
690
694
  }
691
695
  getByPoint(hitPoint, hitRadius, options) {
692
696
  if (Platform.name === 'node')
693
697
  this.target.emit(LayoutEvent.CHECK_UPDATE);
694
- return this.findPath.getByPoint(hitPoint, hitRadius, options);
695
- }
696
- find(name, branch) {
697
- if (typeof name === 'number') {
698
- return this.getByInnerId(name, branch);
699
- }
700
- else if (name.startsWith('#')) {
701
- return this.getById(name.substring(1), branch);
702
- }
703
- else if (name.startsWith('.')) {
704
- return this.getByClassName(name.substring(1), branch);
705
- }
706
- else {
707
- return this.getByTagName(name, branch);
698
+ return this.pather.getByPoint(hitPoint, hitRadius, options);
699
+ }
700
+ getBy(condition, branch, one, options) {
701
+ switch (typeof condition) {
702
+ case 'number':
703
+ const leaf = this.getByInnerId(condition, branch);
704
+ return one ? leaf : (leaf ? [leaf] : []);
705
+ case 'string':
706
+ switch (condition[0]) {
707
+ case '#':
708
+ const leaf = this.getById(condition.substring(1), branch);
709
+ return one ? leaf : (leaf ? [leaf] : []);
710
+ case '.':
711
+ return this.getByMethod(this.methods.className, branch, one, condition.substring(1));
712
+ default:
713
+ return this.getByMethod(this.methods.tag, branch, one, condition);
714
+ }
715
+ case 'function':
716
+ return this.getByMethod(condition, branch, one, options);
708
717
  }
709
718
  }
710
- getByInnerId(name, branch) {
711
- let cache = this.innerIdList[name];
719
+ getByInnerId(innerId, branch) {
720
+ const cache = this.innerIdMap[innerId];
712
721
  if (cache)
713
722
  return cache;
714
- if (!branch)
715
- branch = this.target;
716
- let find;
717
- this.loopFind(branch, (leaf) => {
718
- if (leaf.innerId === name) {
719
- find = leaf;
720
- this.innerIdList[name] = find;
721
- return true;
722
- }
723
- else {
724
- return false;
725
- }
726
- });
727
- return find;
723
+ this.eachFind(this.toChildren(branch), this.methods.innerId, null, innerId);
724
+ return this.findLeaf;
728
725
  }
729
- getById(name, branch) {
730
- let cache = this.idList[name];
731
- if (cache)
726
+ getById(id, branch) {
727
+ const cache = this.idMap[id];
728
+ if (cache && LeafHelper.hasParent(cache, branch || this.target))
732
729
  return cache;
733
- if (!branch)
734
- branch = this.target;
735
- let find;
736
- this.loopFind(branch, (leaf) => {
737
- if (leaf.id === name) {
738
- find = leaf;
739
- this.idList[name] = find;
740
- return true;
741
- }
742
- else {
743
- return false;
744
- }
745
- });
746
- return find;
747
- }
748
- getByClassName(name, branch) {
749
- if (!branch)
750
- branch = this.target;
751
- let find = [];
752
- this.loopFind(branch, (leaf) => {
753
- if (leaf.className === name)
754
- find.push(leaf);
755
- return false;
756
- });
757
- return find;
758
- }
759
- getByTagName(name, branch) {
760
- if (!branch)
761
- branch = this.target;
762
- let find = [];
763
- this.loopFind(branch, (leaf) => {
764
- if (leaf.__tag === name)
765
- find.push(leaf);
766
- return false;
767
- });
768
- return find;
730
+ this.eachFind(this.toChildren(branch), this.methods.id, null, id);
731
+ return this.findLeaf;
769
732
  }
770
- loopFind(branch, find) {
771
- if (find(branch))
772
- return;
773
- const { children } = branch;
733
+ getByClassName(className, branch) {
734
+ return this.getByMethod(this.methods.className, branch, false, className);
735
+ }
736
+ getByTag(tag, branch) {
737
+ return this.getByMethod(this.methods.tag, branch, false, tag);
738
+ }
739
+ getByMethod(method, branch, one, options) {
740
+ const list = one ? null : [];
741
+ this.eachFind(this.toChildren(branch), method, list, options);
742
+ return list || this.findLeaf;
743
+ }
744
+ eachFind(children, method, list, options) {
745
+ let child;
774
746
  for (let i = 0, len = children.length; i < len; i++) {
775
- branch = children[i];
776
- if (find(branch))
777
- return;
778
- if (branch.isBranch)
779
- this.loopFind(branch, find);
747
+ child = children[i];
748
+ if (method(child, options)) {
749
+ if (list) {
750
+ list.push(child);
751
+ }
752
+ else {
753
+ this.findLeaf = child;
754
+ return;
755
+ }
756
+ }
757
+ if (child.isBranch)
758
+ this.eachFind(child.children, method, list, options);
780
759
  }
781
760
  }
761
+ toChildren(branch) {
762
+ this.findLeaf = null;
763
+ return [branch || this.target];
764
+ }
782
765
  __onRemoveChild(event) {
783
- const target = event.target;
784
- if (this.idList[target.id])
785
- this.idList[target.id] = null;
786
- if (this.innerIdList[target.id])
787
- this.innerIdList[target.innerId] = null;
766
+ const { id, innerId } = event.child;
767
+ if (this.idMap[id])
768
+ delete this.idMap[id];
769
+ if (this.innerIdMap[innerId])
770
+ delete this.innerIdMap[innerId];
771
+ }
772
+ __checkIdChange(event) {
773
+ if (event.attrName === 'id') {
774
+ const id = event.oldValue;
775
+ if (this.idMap[id])
776
+ delete this.idMap[id];
777
+ }
788
778
  }
789
779
  __listenEvents() {
790
780
  this.__eventIds = [
791
- this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this)
781
+ this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this),
782
+ this.target.on_(PropertyEvent.CHANGE, this.__checkIdChange, this)
792
783
  ];
793
784
  }
794
785
  __removeListenEvents() {
@@ -798,11 +789,10 @@ class Selector {
798
789
  destroy() {
799
790
  if (this.__eventIds.length) {
800
791
  this.__removeListenEvents();
801
- this.findPath.destroy();
802
- this.innerIdList = {};
803
- this.idList = {};
804
- this.classNameList = {};
805
- this.tagNameList = {};
792
+ this.pather.destroy();
793
+ this.findLeaf = null;
794
+ this.innerIdMap = {};
795
+ this.idMap = {};
806
796
  }
807
797
  }
808
798
  }
@@ -1024,7 +1014,7 @@ const WheelEventHelper = {
1024
1014
  let { zoomMode, zoomSpeed } = config;
1025
1015
  const delta = e.deltaY || e.deltaX;
1026
1016
  if (zoomMode) {
1027
- zoom = !e.deltaX && (Platform.intWheelDeltaY ? Math.abs(delta) > 17 : Math.ceil(delta) !== delta);
1017
+ zoom = (zoomMode === 'mouse') ? true : (!e.deltaX && (Platform.intWheelDeltaY ? Math.abs(delta) > 17 : Math.ceil(delta) !== delta));
1028
1018
  if (e.shiftKey || e.metaKey || e.ctrlKey)
1029
1019
  zoom = true;
1030
1020
  }
@@ -1653,8 +1643,9 @@ function checkImage(ui, canvas, paint, allowPaint) {
1653
1643
  if (!paint.patternTask) {
1654
1644
  paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1655
1645
  paint.patternTask = null;
1656
- if (canvas.bounds.hit(ui.__world) && createPattern(ui, paint, canvas.pixelRatio))
1657
- ui.forceUpdate('surface');
1646
+ if (canvas.bounds.hit(ui.__world))
1647
+ createPattern(ui, paint, canvas.pixelRatio);
1648
+ ui.forceUpdate('surface');
1658
1649
  }), 300);
1659
1650
  }
1660
1651
  }
@@ -2318,6 +2309,8 @@ function createRows(drawData, content, style) {
2318
2309
  const { width, height } = bounds;
2319
2310
  const charMode = width || height || __letterSpacing || (textCase !== 'none');
2320
2311
  if (charMode) {
2312
+ const wrap = style.textWrap !== 'none';
2313
+ const breakAll = style.textWrap === 'break';
2321
2314
  paraStart = true;
2322
2315
  lastCharType = null;
2323
2316
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
@@ -2344,16 +2337,23 @@ function createRows(drawData, content, style) {
2344
2337
  langBreak = (charType === Single && (lastCharType === Single || lastCharType === Letter)) || (lastCharType === Single && charType !== After);
2345
2338
  afterBreak = ((charType === Before || charType === Single) && (lastCharType === Symbol || lastCharType === After));
2346
2339
  realWidth = paraStart && paraIndent ? width - paraIndent : width;
2347
- if (width && rowWidth + wordWidth + charWidth > realWidth) {
2348
- if (!afterBreak)
2349
- afterBreak = charType === Letter && lastCharType == After;
2350
- if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2340
+ if (wrap && (width && rowWidth + wordWidth + charWidth > realWidth)) {
2341
+ if (breakAll) {
2351
2342
  if (wordWidth)
2352
2343
  addWord();
2353
2344
  addRow();
2354
2345
  }
2355
2346
  else {
2356
- addRow();
2347
+ if (!afterBreak)
2348
+ afterBreak = charType === Letter && lastCharType == After;
2349
+ if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2350
+ if (wordWidth)
2351
+ addWord();
2352
+ addRow();
2353
+ }
2354
+ else {
2355
+ addRow();
2356
+ }
2357
2357
  }
2358
2358
  }
2359
2359
  if (char === ' ' && paraStart !== true && (rowWidth + wordWidth) === 0) ;
@@ -2423,7 +2423,7 @@ function addRow() {
2423
2423
 
2424
2424
  const CharMode = 0;
2425
2425
  const WordMode = 1;
2426
- const RowMode = 2;
2426
+ const TextMode = 2;
2427
2427
  function layoutChar(drawData, style, width, _height) {
2428
2428
  const { rows } = drawData;
2429
2429
  const { textAlign, paraIndent, letterSpacing } = style;
@@ -2432,15 +2432,12 @@ function layoutChar(drawData, style, width, _height) {
2432
2432
  if (row.words) {
2433
2433
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0;
2434
2434
  addWordWidth = (width && textAlign === 'justify' && row.words.length > 1) ? (width - row.width - indentWidth) / (row.words.length - 1) : 0;
2435
- mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : RowMode);
2436
- if (mode === RowMode) {
2437
- row.text = '';
2435
+ mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : TextMode);
2436
+ if (row.isOverflow && !letterSpacing)
2437
+ row.textMode = true;
2438
+ if (mode === TextMode) {
2438
2439
  row.x += indentWidth;
2439
- row.words.forEach(word => {
2440
- word.data.forEach(char => {
2441
- row.text += char.char;
2442
- });
2443
- });
2440
+ toTextChar$1(row);
2444
2441
  }
2445
2442
  else {
2446
2443
  row.x += indentWidth;
@@ -2466,6 +2463,14 @@ function layoutChar(drawData, style, width, _height) {
2466
2463
  }
2467
2464
  });
2468
2465
  }
2466
+ function toTextChar$1(row) {
2467
+ row.text = '';
2468
+ row.words.forEach(word => {
2469
+ word.data.forEach(char => {
2470
+ row.text += char.char;
2471
+ });
2472
+ });
2473
+ }
2469
2474
  function toWordChar(data, charX, wordChar) {
2470
2475
  data.forEach(char => {
2471
2476
  wordChar.char += char.char;
@@ -2486,10 +2491,10 @@ function toChar(data, charX, rowData) {
2486
2491
 
2487
2492
  function layoutText(drawData, style) {
2488
2493
  const { rows, bounds } = drawData;
2489
- const { __lineHeight, __baseLine, __letterSpacing, textAlign, verticalAlign, paraSpacing, textOverflow } = style;
2494
+ const { __lineHeight, __baseLine, __letterSpacing, __clipText, textAlign, verticalAlign, paraSpacing } = style;
2490
2495
  let { x, y, width, height } = bounds, realHeight = __lineHeight * rows.length + (paraSpacing ? paraSpacing * (drawData.paraNumber - 1) : 0);
2491
2496
  let starY = __baseLine;
2492
- if (textOverflow !== 'show' && realHeight > height) {
2497
+ if (__clipText && realHeight > height) {
2493
2498
  realHeight = Math.max(height, __lineHeight);
2494
2499
  drawData.overflow = rows.length;
2495
2500
  }
@@ -2538,39 +2543,58 @@ function layoutText(drawData, style) {
2538
2543
  bounds.x = rowX;
2539
2544
  if (rowWidth > bounds.width)
2540
2545
  bounds.width = rowWidth;
2546
+ if (__clipText && width && width < rowWidth) {
2547
+ row.isOverflow = true;
2548
+ if (!drawData.overflow)
2549
+ drawData.overflow = rows.length;
2550
+ }
2541
2551
  }
2542
2552
  bounds.y = y;
2543
2553
  bounds.height = realHeight;
2544
2554
  }
2545
2555
 
2546
- function clipText(drawData, textOverflow) {
2556
+ function clipText(drawData, style) {
2547
2557
  const { rows, overflow } = drawData;
2558
+ let { textOverflow } = style;
2548
2559
  rows.splice(overflow);
2549
2560
  if (textOverflow !== 'hide') {
2550
2561
  if (textOverflow === 'ellipsis')
2551
2562
  textOverflow = '...';
2563
+ let char, charRight;
2552
2564
  const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2553
- const row = rows[overflow - 1];
2554
- let char, end = row.data.length - 1, charRight;
2555
- const { x, width } = drawData.bounds;
2556
- const right = x + width - ellipsisWidth;
2557
- for (let i = end; i > -1; i--) {
2558
- char = row.data[i];
2559
- charRight = char.x + char.width;
2560
- if (i === end && charRight < right) {
2561
- break;
2562
- }
2563
- else if (charRight < right && char.char !== ' ') {
2564
- row.data.splice(i + 1);
2565
- row.width -= char.width;
2566
- break;
2565
+ const right = style.x + style.width - ellipsisWidth;
2566
+ const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2567
+ list.forEach(row => {
2568
+ if (row.isOverflow && row.data) {
2569
+ let end = row.data.length - 1;
2570
+ for (let i = end; i > -1; i--) {
2571
+ char = row.data[i];
2572
+ charRight = char.x + char.width;
2573
+ if (i === end && charRight < right) {
2574
+ break;
2575
+ }
2576
+ else if (charRight < right && char.char !== ' ') {
2577
+ row.data.splice(i + 1);
2578
+ row.width -= char.width;
2579
+ break;
2580
+ }
2581
+ row.width -= char.width;
2582
+ }
2583
+ row.width += ellipsisWidth;
2584
+ row.data.push({ char: textOverflow, x: charRight });
2585
+ if (row.textMode)
2586
+ toTextChar(row);
2567
2587
  }
2568
- row.width -= char.width;
2569
- }
2570
- row.width += ellipsisWidth;
2571
- row.data.push({ char: textOverflow, x: charRight });
2588
+ });
2572
2589
  }
2573
2590
  }
2591
+ function toTextChar(row) {
2592
+ row.text = '';
2593
+ row.data.forEach(char => {
2594
+ row.text += char.char;
2595
+ });
2596
+ row.data = null;
2597
+ }
2574
2598
 
2575
2599
  function decorationText(drawData, style) {
2576
2600
  const { fontSize } = style;
@@ -2591,7 +2615,7 @@ const TextConvert = {
2591
2615
  let x = 0, y = 0;
2592
2616
  let width = style.__getInput('width') || 0;
2593
2617
  let height = style.__getInput('height') || 0;
2594
- const { textDecoration, textOverflow, __font, padding } = style;
2618
+ const { textDecoration, __font, padding } = style;
2595
2619
  if (padding) {
2596
2620
  const [top, right, bottom, left] = MathHelper.fourNumber(padding);
2597
2621
  if (width) {
@@ -2613,7 +2637,7 @@ const TextConvert = {
2613
2637
  layoutText(drawData, style);
2614
2638
  layoutChar(drawData, style, width);
2615
2639
  if (drawData.overflow)
2616
- clipText(drawData, textOverflow);
2640
+ clipText(drawData, style);
2617
2641
  if (textDecoration !== 'none')
2618
2642
  decorationText(drawData, style);
2619
2643
  return drawData;