danielsaidi / RichTextKit

RichTextKit is a Swift SDK that helps you use rich text in Swift and SwiftUI.
MIT License
949 stars 126 forks source link

How to apply modifier to button? #152

Open alelordelo opened 9 months ago

alelordelo commented 9 months ago

On the code bellow, I can apply a modifier to the buttonStyle:

.buttonStyle(.plain)

//
//  RichTextActionButton.swift
//  RichTextKit
//
//  Created by Daniel Saidi on 2022-12-08.
//  Copyright © 2022-2024 Daniel Saidi. All rights reserved.
//

import SwiftUI

public extension RichTextAction {

    /**
     This button can be used to trigger a ``RichTextAction``.

     This renders a plain `Button`, which means that you can
     use and configure it as a normal button.
     */
    struct Button: View {
        /**
         Create a rich text action button.

         - Parameters:
           - action: The action to trigger.
           - context: The context to affect.
           - fillVertically: WhetherP or not fill up vertical space, by default `false`.
         */
        public init(
            action: RichTextAction,
            context: RichTextContext,
            fillVertically: Bool = false
        ) {
            self.action = action
            self._context = ObservedObject(wrappedValue: context)
            self.fillVertically = fillVertically
        }

        private let action: RichTextAction
        private let fillVertically: Bool

        @ObservedObject
        private var context: RichTextCo
<img width="1252" alt="Screenshot 2024-02-29 at 18 12 23" src="https://github.com/danielsaidi/RichTextKit/assets/17708751/5655f55d-a7c0-43ec-b82a-e6d8bf840727">
ntext

        public var body: some View {
            SwiftUI.Button(action: triggerAction) {
                action.label
                    .labelStyle(.iconOnly)
                    .frame(maxHeight: fillVertically ? .infinity : nil)
                    .contentShape(Rectangle())
            }
            .buttonStyle(.plain)

            .keyboardShortcut(for: action)
            .disabled(!context.canHandle(action))
        }

    }
}

It gets added to the preview:

Screenshot 2024-02-29 at 18 12 23 Screenshot 2024-02-29 at 18 12 12

But when I build the app, it shows the default button style.

Screenshot 2024-02-29 at 18 17 01

How can I apply a modifier and change the button style?

DominikBucher12 commented 9 months ago

hello @alelordelo

are you sure its the background of the button and not RichTextStyle.ToggleStack? Btw I strongly encourage you not to modify the already existing components, which are made for pure sdk usage but rather use custom buttons and stacks which suits your need.

Snímek obrazovky 2024-02-29 v 23 02 39

For iOS:

Inside RichTextStyle+ToggleStack.swift:

 public var body: some View {
            HStack(spacing: spacing) {
                ForEach(styles) {
                    RichTextStyle.Toggle(
                        style: $0,
                        context: context,
                        fillVertically: true
                    )
                }
            }
           >>>>>>> .background(.green) // This line of code.
            .fixedSize(horizontal: false, vertical: true)
        }

For macOS:

in RichTextStyle+ToggleGroup.swift

 public var body: some View {
            #if macOS
            ControlGroup {
                ForEach(styles) {
                    RichTextStyle.Toggle(
                        style: $0,
                        context: context,
                        fillVertically: true
                    )
                }
            }
          >>>>>>>>>>>  .controlGroupStyle(.navigation) // insert different style.
            .frame(width: groupWidth)
            #else
            RichTextStyle.ToggleStack(
                context: context,
                styles: styles
            )
            #endif
        }
    }

Together with your button change, otherwise this happens:

Snímek obrazovky 2024-02-29 v 23 10 38

Hope this helps and let me know if I can close this issue :)

danielsaidi commented 9 months ago

I will introduce a style concept in later versions, where we'll be able to inject library-specific styles into the environment. Button styles won't work consistently, since some component needs to apply specific button styles within the components.

alelordelo commented 9 months ago

_Btw I strongly encourage you not to modify the already existing components, which are made for pure sdk usage but rather use custom buttons and stacks which suits your need.__ But is there a way to set a SwiftUI button style (not custom style) at the library level (not modifying library internally)?

_are you sure its the background of the button and not RichTextStyle.ToggleStack? I need to set all buttons as .buttonStyle(.plain) (not change its background) to match all the other buttons I have. I am going thought all buttons internally and setting to .buttonStyle(.plain)

All of them change on Xcode preview when I set to .buttonStyle(.plain). But some change when I build the app, and some not, ex:

Here I changed the Toggle:

        private var toggle: some View {
            SwiftUI.Toggle(isOn: value) {
                style.icon
                    .frame(maxHeight: fillVertically ? .infinity : nil)
            }        .buttonStyle(.plain)

            .keyboardShortcut(for: style)
            .accessibilityLabel(style.title)
        }
Screenshot 2024-03-01 at 10 11 22

Google change is not reflected on the app, while the Font picker is:

Screenshot 2024-03-01 at 10 07 20
DominikBucher12 commented 9 months ago

I strongly believe the API of the RichTextKit (at least the core part) is so scalable, that it is easier (and more convenient) for API consumers not to use and try to modify the existing components but to create their own SwiftUI components where they inject just the context as ObservableObject and do the toggling on their own.

In my other project, I created custom toolbar which accept the context and basically observes the context and I can have even progressView or something else which on each value of the slider, can have different attribute for the range.

If you can wait, I will create Demo example and post it in here (or in the project) with description how to use context in order to create Api-Consumer UIViews.

but the basic idea is:

public struct MyCustomRichTextView: View {
    @State private var text: NSAttributedString
    @State private var context: RichTextContext
    private let configuration: RichTextView.Configuration
    private let theme: RichTextView.Theme
    private let subtitle: String?

    public var body: some View {
        VStack {
                RichTextEditor(
                    text: $text,
                    context: context,
                    config: .standard,
                    theme: theme,
                    format: .rtf
                )
                .cornerRadius(8)
                .clipped()
                 MyCustomCommandView(context: context)
        }
    }

where: MyCustomCommandView(context: context) is your implementation with custom buttons etc reacting to context changes...

ANYWAY!

All possibilities.

  1. Copy the library to be under your control and modify the internals on your own, having 100% control of the library... if you are wanting to change just the simple styles and keep it that way, I see this as a good fit. But the big downside of this is that it might break later because of Library updates + new features, so this seems not scalable for you
  2. Create a PR with changes (injecting viewStyle to SwiftUI Views) as I am currently busy with TextKit/Texkit2 + Bullet points and want really to finish links, I do not have time for supporting this UI, but I am happy to review
  3. Implement your custom UI with context injection as suggested.
  4. Wait for this issue (as clearly I do not see it as priority right no, dunno about @danielsaidi ) to be resolved by us.

Hope this helps!

alelordelo commented 9 months ago

Thanks again @DominikBucher12 !

1 - this is what I am doing atm. But there are so many layers of abstraction that even applying a simple button modifier is super hard. The example above worked for some buttons, not not to others. Any idea why?

3- would be super helpful if you can point how to inject a button modifier for ex.

alelordelo commented 9 months ago

IMG_0882

danielsaidi commented 1 month ago

How are we on this issue?