@almadar/std 16.184.0 → 16.186.0

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.
@@ -1,5 +1,5 @@
1
1
  app std-rich-editor "1.0.0"
2
- "std-rich-editor — wiki/CMS Notion-style block editor. Browses documents in `browsing`; opens the rich-block-editor on a selected row; persists block edits + publish status. `BlockEdit` is a rebindable single-row overlay editor: an organism rebinds it to its own entity (WikiPage, Note, …), passes the row's id + blocksJson via OPEN, and routes the emitted BLOCKS_SAVED into its own persistor — this atom never fetches or persists."
2
+ "std-rich-editor — wiki/CMS Notion-style block editor. Browses documents in `browsing`; opens the rich-block-editor on a selected row; persists block edits + publish status. `BlockEdit` is a rebindable single-row IN-PLACE body editor: an organism embeds it where the content belongs, rebinds it to its own entity (WikiPage, Note, …), hands it the row's id + blocksJson via OPEN, and routes the emitted BLOCKS_SAVED into its own persistor — this atom never fetches or persists. The read-only body is itself the edit affordance; an empty row paints an empty state that starts the first block; and OPEN_DRAFT opens straight into the authoring editor for a row that was just minted blank (document-first creation)."
3
3
  ;; @capabilities "notes app, note-taking, journal, personal journal entries, document editor, write and organize notes"
4
4
  type BlockSpec = { type : string!, content : string, id : string }
5
5
  type ObjectSpec = { id : string, label : string, value : string }
@@ -419,35 +419,88 @@ orbital DocumentOrbital {
419
419
  }
420
420
  }
421
421
 
422
+ ;; In-place body editor for one row. The composing organism embeds this
423
+ ;; trait where the content belongs (`<trait.X />` inside its detail
424
+ ;; render) and feeds it the loaded row through OPEN; the body paints
425
+ ;; read-only AND is its own edit affordance — clicking it enters editing
426
+ ;; with the authoring toolbar, and a row with no blocks yet paints an
427
+ ;; empty state whose button starts the first one. OPEN_DRAFT is the
428
+ ;; document-first entry: same payload, but it lands in the editor. SAVE
429
+ ;; emits BLOCKS_SAVED for the host's persistor; this atom never fetches or
430
+ ;; persists.
422
431
  trait BlockEdit -> @rebindable Document [interaction, instance] {
423
432
  initial: idle
424
433
 
425
434
  state idle {
426
435
  INIT -> idle
427
- OPEN -> editing
436
+ OPEN -> viewing when [">", (array/len ?blocksJson), 0]
428
437
  (set @entity.id ?id)
429
438
  (set @entity.blocksJson ?blocksJson)
430
- (render-ui modal {
439
+ (render-ui main {
440
+ children: [{
441
+ children: [{
442
+ action: EDIT_BLOCKS
443
+ icon: edit
444
+ label: @config.editLabel
445
+ type: button
446
+ variant: secondary
447
+ }]
448
+ direction: horizontal
449
+ gap: sm
450
+ justify: end
451
+ type: stack
452
+ }, {
453
+ action: EDIT_BLOCKS
454
+ children: [{
455
+ initialBlocks: @entity.blocksJson
456
+ readOnly: true
457
+ type: rich-block-editor
458
+ }]
459
+ className: "cursor-text rounded-md transition-colors hover:bg-muted/40"
460
+ type: box
461
+ }]
462
+ direction: vertical
463
+ gap: sm
464
+ type: stack
465
+ })
466
+ OPEN -> viewing when ["=", (array/len ?blocksJson), 0]
467
+ (set @entity.id ?id)
468
+ (set @entity.blocksJson ?blocksJson)
469
+ (render-ui main {
470
+ actionEvent: EDIT_BLOCKS
471
+ actionLabel: @config.emptyActionLabel
472
+ description: @config.emptyDescription
473
+ icon: file-text
474
+ title: @config.emptyTitle
475
+ type: empty-state
476
+ })
477
+ ;; Document-first entry: the row was just minted as a blank draft, so
478
+ ;; the body opens ALREADY authoring instead of painting an empty state
479
+ ;; the author has to click through. A distinct trigger, not a flag on
480
+ ;; OPEN — the guard surface stays decidable.
481
+ OPEN_DRAFT -> editing
482
+ (set @entity.id ?id)
483
+ (set @entity.blocksJson ?blocksJson)
484
+ (render-ui main {
431
485
  children: [{
432
486
  align: center
433
487
  children: [{ name: file-text, type: icon }, {
434
488
  content: @config.title
435
489
  type: typography
436
- variant: h3
490
+ variant: h4
437
491
  }]
438
492
  direction: horizontal
439
493
  gap: sm
440
494
  type: stack
441
- }, { type: divider }, {
495
+ }, {
442
496
  changeEvent: BLOCKS_CHANGE
443
497
  initialBlocks: @entity.blocksJson
444
498
  placeholder: @config.placeholder
445
499
  showToolbar: true
446
500
  type: rich-block-editor
447
501
  }, {
448
- align: center
449
502
  children: [{
450
- action: SAVE
503
+ action: SAVE_BLOCKS
451
504
  label: Save
452
505
  type: button
453
506
  variant: primary
@@ -459,6 +512,7 @@ orbital DocumentOrbital {
459
512
  }]
460
513
  direction: horizontal
461
514
  gap: sm
515
+ justify: end
462
516
  type: stack
463
517
  }]
464
518
  direction: vertical
@@ -470,14 +524,190 @@ orbital DocumentOrbital {
470
524
  BLOCKS_SAVED -> idle
471
525
  }
472
526
 
527
+ state viewing {
528
+ OPEN_DRAFT -> editing
529
+ (set @entity.id ?id)
530
+ (set @entity.blocksJson ?blocksJson)
531
+ (render-ui main {
532
+ children: [{
533
+ align: center
534
+ children: [{ name: file-text, type: icon }, {
535
+ content: @config.title
536
+ type: typography
537
+ variant: h4
538
+ }]
539
+ direction: horizontal
540
+ gap: sm
541
+ type: stack
542
+ }, {
543
+ changeEvent: BLOCKS_CHANGE
544
+ initialBlocks: @entity.blocksJson
545
+ placeholder: @config.placeholder
546
+ showToolbar: true
547
+ type: rich-block-editor
548
+ }, {
549
+ children: [{
550
+ action: SAVE_BLOCKS
551
+ label: Save
552
+ type: button
553
+ variant: primary
554
+ }, {
555
+ action: CLOSE
556
+ label: Cancel
557
+ type: button
558
+ variant: ghost
559
+ }]
560
+ direction: horizontal
561
+ gap: sm
562
+ justify: end
563
+ type: stack
564
+ }]
565
+ direction: vertical
566
+ gap: md
567
+ type: stack
568
+ })
569
+ OPEN -> viewing when [">", (array/len ?blocksJson), 0]
570
+ (set @entity.id ?id)
571
+ (set @entity.blocksJson ?blocksJson)
572
+ (render-ui main {
573
+ children: [{
574
+ children: [{
575
+ action: EDIT_BLOCKS
576
+ icon: edit
577
+ label: @config.editLabel
578
+ type: button
579
+ variant: secondary
580
+ }]
581
+ direction: horizontal
582
+ gap: sm
583
+ justify: end
584
+ type: stack
585
+ }, {
586
+ action: EDIT_BLOCKS
587
+ children: [{
588
+ initialBlocks: @entity.blocksJson
589
+ readOnly: true
590
+ type: rich-block-editor
591
+ }]
592
+ className: "cursor-text rounded-md transition-colors hover:bg-muted/40"
593
+ type: box
594
+ }]
595
+ direction: vertical
596
+ gap: sm
597
+ type: stack
598
+ })
599
+ OPEN -> viewing when ["=", (array/len ?blocksJson), 0]
600
+ (set @entity.id ?id)
601
+ (set @entity.blocksJson ?blocksJson)
602
+ (render-ui main {
603
+ actionEvent: EDIT_BLOCKS
604
+ actionLabel: @config.emptyActionLabel
605
+ description: @config.emptyDescription
606
+ icon: file-text
607
+ title: @config.emptyTitle
608
+ type: empty-state
609
+ })
610
+ EDIT_BLOCKS -> editing
611
+ (render-ui main {
612
+ children: [{
613
+ align: center
614
+ children: [{ name: file-text, type: icon }, {
615
+ content: @config.title
616
+ type: typography
617
+ variant: h4
618
+ }]
619
+ direction: horizontal
620
+ gap: sm
621
+ type: stack
622
+ }, {
623
+ changeEvent: BLOCKS_CHANGE
624
+ initialBlocks: @entity.blocksJson
625
+ placeholder: @config.placeholder
626
+ showToolbar: true
627
+ type: rich-block-editor
628
+ }, {
629
+ children: [{
630
+ action: SAVE_BLOCKS
631
+ label: Save
632
+ type: button
633
+ variant: primary
634
+ }, {
635
+ action: CLOSE
636
+ label: Cancel
637
+ type: button
638
+ variant: ghost
639
+ }]
640
+ direction: horizontal
641
+ gap: sm
642
+ justify: end
643
+ type: stack
644
+ }]
645
+ direction: vertical
646
+ gap: md
647
+ type: stack
648
+ })
649
+ }
650
+
473
651
  state editing {
474
652
  BLOCKS_CHANGE -> editing
475
653
  (set @entity.blocksJson ?blocks)
476
- SAVE -> idle
477
- (render-ui modal null)
654
+ SAVE_BLOCKS -> viewing
478
655
  (emit BLOCKS_SAVED { id: @entity.id, blocksJson: @entity.blocksJson })
479
- CLOSE -> idle
480
- (render-ui modal null)
656
+ (render-ui main {
657
+ children: [{
658
+ children: [{
659
+ action: EDIT_BLOCKS
660
+ icon: edit
661
+ label: @config.editLabel
662
+ type: button
663
+ variant: secondary
664
+ }]
665
+ direction: horizontal
666
+ gap: sm
667
+ justify: end
668
+ type: stack
669
+ }, {
670
+ action: EDIT_BLOCKS
671
+ children: [{
672
+ initialBlocks: @entity.blocksJson
673
+ readOnly: true
674
+ type: rich-block-editor
675
+ }]
676
+ className: "cursor-text rounded-md transition-colors hover:bg-muted/40"
677
+ type: box
678
+ }]
679
+ direction: vertical
680
+ gap: sm
681
+ type: stack
682
+ })
683
+ CLOSE -> viewing
684
+ (render-ui main {
685
+ children: [{
686
+ children: [{
687
+ action: EDIT_BLOCKS
688
+ icon: edit
689
+ label: @config.editLabel
690
+ type: button
691
+ variant: secondary
692
+ }]
693
+ direction: horizontal
694
+ gap: sm
695
+ justify: end
696
+ type: stack
697
+ }, {
698
+ action: EDIT_BLOCKS
699
+ children: [{
700
+ initialBlocks: @entity.blocksJson
701
+ readOnly: true
702
+ type: rich-block-editor
703
+ }]
704
+ className: "cursor-text rounded-md transition-colors hover:bg-muted/40"
705
+ type: box
706
+ }]
707
+ direction: vertical
708
+ gap: sm
709
+ type: stack
710
+ })
481
711
  }
482
712
 
483
713
  emits {
@@ -489,7 +719,7 @@ orbital DocumentOrbital {
489
719
  @synonyms "saved, persist, update, commit"
490
720
  @tier "domain"
491
721
  CLOSE
492
- @description "Indicates the block editor overlay is being dismissed."
722
+ @description "Leaves the editor without saving; the body returns to its read-only render."
493
723
  @synonyms "dismiss, hide, cancel, close"
494
724
  @tier "domain"
495
725
  BLOCKS_CHANGE {
@@ -505,9 +735,16 @@ orbital DocumentOrbital {
505
735
  id : string!
506
736
  blocksJson : [BlockSpec]
507
737
  }
508
- @description "Requests the block editor overlay open for the given row. The caller supplies the row's id and current blocks — this trait never fetches them itself."
738
+ @description "Hands the editor the row whose body it renders — the caller supplies the row's id and current blocks, since this trait never fetches them itself. Re-firing it repaints the body (e.g. after the host refetches a saved row)."
509
739
  @synonyms "show, launch, reveal, edit"
510
740
  @tier "domain"
741
+ OPEN_DRAFT {
742
+ id : string!
743
+ blocksJson : [BlockSpec]
744
+ }
745
+ @description "Hands the editor a row that was just created as a blank draft: same payload as OPEN, but the body opens straight in the authoring editor instead of the read-only render, so a document-first 'New page' lands the author on a cursor rather than an empty state."
746
+ @synonyms "new document, start writing, blank draft, compose"
747
+ @tier "domain"
511
748
  BLOCKS_CHANGE {
512
749
  blocks : [BlockSpec]
513
750
  }
@@ -515,7 +752,7 @@ orbital DocumentOrbital {
515
752
  @synonyms "update, modify, edit"
516
753
  @tier "domain"
517
754
  CLOSE
518
- @description "Indicates the block editor overlay is being dismissed."
755
+ @description "Leaves the editor without saving; the body returns to its read-only render."
519
756
  @synonyms "dismiss, hide, cancel, close"
520
757
  @tier "domain"
521
758
  }
@@ -523,12 +760,28 @@ orbital DocumentOrbital {
523
760
  config {
524
761
  title : string = "Edit content"
525
762
  @label "Editor heading"
526
- @description "Heading shown at the top of the block editor overlay."
763
+ @description "Heading shown above the editor while the body is being edited."
527
764
  @tier "presentation"
528
765
  placeholder : string = "Start writing…"
529
766
  @label "Placeholder text"
530
767
  @description "Placeholder shown in the block editor when it is empty."
531
768
  @tier "presentation"
769
+ editLabel : string = "Edit content"
770
+ @label "Edit button label"
771
+ @description "Label of the button above the read-only body that opens the editor."
772
+ @tier "presentation"
773
+ emptyTitle : string = "Nothing written yet"
774
+ @label "Empty heading"
775
+ @description "Heading shown in place of the body when the row has no blocks yet."
776
+ @tier "presentation"
777
+ emptyDescription : string = "This page has no content yet. Start writing to fill it in."
778
+ @label "Empty description"
779
+ @description "Supporting line shown with the empty body state."
780
+ @tier "presentation"
781
+ emptyActionLabel : string = "Start writing"
782
+ @label "Empty action label"
783
+ @description "Label of the button that opens the editor from the empty body state."
784
+ @tier "presentation"
532
785
  }
533
786
  }
534
787
 
@@ -78,6 +78,7 @@ orbital DetailPanelOrbital {
78
78
  selectedIds: @config.selectedIds
79
79
  entity: @entity
80
80
  title: @config.title
81
+ onTitleCommit: @config.onTitleCommit
81
82
  subtitle: @config.subtitle
82
83
  status: @config.status
83
84
  avatar: @config.avatar
@@ -113,6 +114,7 @@ orbital DetailPanelOrbital {
113
114
  selectedIds: @config.selectedIds
114
115
  entity: @payload.data
115
116
  title: @config.title
117
+ onTitleCommit: @config.onTitleCommit
116
118
  subtitle: @config.subtitle
117
119
  status: @config.status
118
120
  avatar: @config.avatar
@@ -192,6 +194,10 @@ orbital DetailPanelOrbital {
192
194
  @label "Title"
193
195
  @description "title prop"
194
196
  @tier "presentation"
197
+ onTitleCommit : string = ""
198
+ @label "On Title Commit"
199
+ @description "When bound, the title becomes editable in place: clicking it swaps the heading for an input, Enter or blur commits, Escape reverts. Receives the committed title and the record's id so the host can persist a partial update. Unbound, the title stays a plain heading."
200
+ @tier "presentation"
195
201
  subtitle : string
196
202
  @label "Subtitle"
197
203
  @description "subtitle prop"